Rest概述
简介
- REST是英文Representational State Transfer(表现层状态转化),Rest是web服务的一种架构风格;
- 使用HTTP,URI、XML、JSON、HTML等广泛流行的标准和协议;轻量级,跨平台、跨语言的架构设计;
- 它是一种设计风格,不是一种标准,是一种思想。
Rest原则
设计思想
REST简化开发,其架构遵循CRUD原则,该原则告诉我们对于资源(包括网络资源)只需要四种行为:创建,获取,更新和删除就可以完成相关的操作和处理。
我们可以通过统一资源标识符(Universal Resource Identifier,URI)来识别和定位资源,并且针对这些资源而执行的操作是通过 HTTP 规范定义的。其核心操作只有GET,POST,PUT,DELETE。也就是:URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。
因此设计web接口的时候,REST主要是用于定义接口名,接口名一般是用名次写,不用动词,那怎么表达“获取”或者“删除”或者“更新”这样的操作呢——用请求类型(GET,PUT,POST,DELETE)来区分。
案例
比如我们设计一个用户管理系统的接口,如果不使用Restful风格,接口会定义如下:
1 |
|
从上面的定义接口来看貌似没有什么问题,但是仔细揣测就会发现有一些瑕疵:比如查询方法定义接口使用了query
动词,而GET
请求本身的含义也就是从服务器获取资源,带有查询的含义,如果接口里面定义又加上这样的动词显得重复,同理其他几个接口也是一样的。
而使用Rest接口定义如下:
1 | http://127.0.0.1/user/1 #GET 根据用户id查询用户数据 |
从上面定义的接口我们可以看出,接口名称主要指向user
资源,具体的资源操作(增删改查)由HTTP的请求类型来定义。这样接口名称显得统一整洁,就不用定义不同的接口名称。
遵循这样一种风格的Reset接口就叫做Restful。
HTTP方法幂等性与安全性
HTTP方法 | 资源操作 | 幂等 | 安全 |
---|---|---|---|
GET | SELECT | 是 | 安全 |
POST | INSERT | 否 | 否 |
PUT | UPDATE | 是 | 否 |
DELETE | DELETE | 是 | 否 |
- 幂等:对同一Rest接口多次请求,得到的资源状态是相同的。
- 安全:对该Rest接口请求,不会使服务器资源状态发生改变。
Rest优势
由于REST强制所有的操作都必须是无状态的,这就没有上下文的约束,如果做分布式,集群都不需要考虑上下文和会话保持的问题。极大的提高系统的可伸缩性。
前后端分离。前端拿到数据只负责展示和渲染,不对数据做任何处理。后端处理数据并以JSON格式传输出去,定义这样一套统一的接口,在web,ios,android三端都可以用相同的接口。
Django接口开发
Django简介
Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的框架模式,即模型M,视图V和控制器C。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件。并于2005年7月在BSD许可证下发布。这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的。
Tips:Python的Web开发框架除了Django,还有Flask和Tornado等。
Django安装
输入如下命令即可安装Django,注意需要提前配置好Python环境,这里选择的django版本是2.0.3版本,
1 | pip install django |
安装校验:在Windows命令提示符下输入django-admin
命令回车。
提示如下内容则说明安装成功1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32C:\Users\Shuqing>django-admin
Type 'django-admin help <subcommand>' for help on a specific subcommand.
Available subcommands:
[django]
check
compilemessages
createcachetable
dbshell
diffsettings
dumpdata
flush
inspectdb
loaddata
makemessages
makemigrations
migrate
runserver
sendtestemail
shell
showmigrations
sqlflush
sqlmigrate
sqlsequencereset
squashmigrations
startapp
startproject
test
testserver
Note that only Django core commands are listed as settings are not properly configured (error: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.)
Django REST Framework
简介
Django REST Framework,是一套基于Django的REST风格的框架。
官方主页:http://www.django-rest-framework.org
特点
- 功能强大、灵活,可以帮助你快速开发Web API。
- 支持认证策略,包括OAuth1和OAuth2。
- 支持ORM(对象关系映射)和非ORM数据源的序列化。
- 丰富的文档以及良好的社区支持。
安装
1 | pip install djangorestframework #Django REST Framework |
创建API
项目创建
当Django REST Framework安装好之后,创建一个新的项目django_restful
,如下命令所示我是创建在D盘根目录。在项目下创建api
应用
1 | C:\Users\Shuqing>d: |
进入项目django_restful
创建api
应用,创建完成之后可以看到项目文件夹下面多了一个api
文件夹1
2
3D:\>cd django_restful
D:\django_restful>python manage.py startapp api
进入到D:\django_rest\django_restful
目录,打开settings.py
在项目下创建api
和rest_framework
。
1 | INSTALLED_APPS = [ |
rest_framework权限配置
默认的权限策略可以设置在全局范围内,通过DEFAULT_PERMISSION_CLASSES
设置。在该文件末尾添加如下内容:
1 | REST_FRAMEWORK = { |
数据库迁移
然后通过命令migrate
命令进行数据库迁移。
1 | D:\django_restful>python manage.py migrate |
执行之后看到如下提示说明迁移成功1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying sessions.0001_initial... OK
创建超级管理员
使用createsuperuser
命令来创建超级管理员账户,密码至少8位数字和字母组合。如51zxw20182018
1 | D:\django_rest>python manage.py createsuperuser |
启动Server
启动django,然后验证登录我们创建的超级管理员账户。
1 | D:\django_rest>python manage.py runserver |
启动成功之后,输入地址:http://127.0.0.1:8000/
我们可以看到如下页面:
Tips:也可以自定义host
和port
,如下所示:
1 | python manage.py runserver 127.0.0.1:8001 |
登录超级管理员账户
我们再输入地址:http://127.0.0.1:8000/admin
即可进入到登录超级管理员账户界面:
登录我们创建的账户,可以看到如下界面:
数据序列化
Serializers用于定义API的表现形式,如返回哪些字段、返回怎样的格式等。这里序列化Django自带的User
和Group
。创建数据序列化,在api应用下创建serializers.py
文件。
序列化代码如下:
serializers.py
1 | from django.contrib.auth.models import User,Group |
创建视图
视图用于如何向用户展示数据,展示哪些数据。比如用户查询User
信息或查询Group
信息,那么程序内部要定义好怎么去查询。在Django REST framework中,ViewSets
用于定义视图的展现形式,例如返回哪些内容,需要做哪些权限处理。
打开api应用下的views.py
文件,编写如下代码:
views.py
1 | from django.shortcuts import render |
在URL中会定义相应的规则到ViewSets
。ViewSets
则通过serializer_class
找到对应的Serializers
。
这里将User
和Group
的所有对象赋予queryset
,并返回这些值。在UserSerializer
和GroupSerializer
中定义要返回的字段。
URL路由配置
打开.../django_rest/urls.py
文件,添加api
的路由配置。
1 | from django.contrib import admin |
注意:Django1.0和2.0关于路由配置写法有一些区别,使用1.0路由配置如下
1 | from django.conf.urls import url |
打开API主页
启动服务,然后在浏览器打开:http://127.0.0.1:8000/
即可看到API主页,如下所示:
创建数据
点击主页右上角的Log in
登录超级管理员账户,然后分别创建Group
和User
数据。
Tips: Vary: Accept
标头可告诉代理服务器缓存两种版本的资源:压缩和非压缩,这有助于避免一些公共代理不能正确地检测Content-Encoding标头的问题。
Swagger接口文档生成
接口开发完成了,那么接下来需要编写接口文档。传统的接口文档编写都是使用Word或者其他一些接口文档管理平台,这种形式接口文档维护更新比较麻烦,每次接口有变动时得手动修改文档。因此,针对这种情况,这里推荐使用Swagger来管理接口文档。
Swagger简介
Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统(源代码)作为服务器以同样的速度来更新。每当接口有变动时,对应的接口文档也会自动更新。
Tips:http://httpbin.org/#/ 也是利用Swagger生成接口文档。
Swagger能成为最受欢迎的REST APIs文档生成工具之一,有以下几个原因:
- Swagger 可以生成一个具有互动性的API控制台,开发者可以用来快速学习和尝试API。
- Swagger 可以生成客户端SDK代码用于各种不同的平台上的实现。
- Swagger 文件可以在许多不同的平台上从代码注释中自动生成。
- Swagger 有一个强大的社区,里面有许多强悍的贡献者。
Django 接入Swagger
首先安装 django-rest-swagger
1 | pip install django-rest-swagger |
进入到setting.py
文件,添加django-rest-swagger
应用
1 | # Application definition |
进入到views.py
将之前定义的UserViewSet
和GroupViewSet
补充注释:
1 |
|
在urls.py
添加get_schema_view
辅助函数
1 | from rest_framework.schemas import get_schema_view |
启动服务,然后打开地址:http://127.0.0.1:8000/docs/
即可看到如下界面:
分别点击groups
和users
即可看到自动生成的接口文档。
Restful接口测试
开发完接口,接下来我们需要对我们开发的接口进行测试。接口测试的方法比较多,使用接口工具或者Python来测试都可以,工具方面比如之前我们学习过的Postman
或者Jmeter
,Python脚本测试可以使用Requests
+ unittest
来测试。
测试思路
- 功能测试:数据的增删改查
- 异常测试:未授权,参数异常等
Postman测试
使用测试工具Postman测试结果如下所示:
user接口测试
查询所有用户
创建用户
修改用户
删除用户
未授权测试
groups接口测试
查询所有groups数据
修改group数据
删除groups
Requests+Unittest
在api
目录下面新建一个test_unittest.py
,代码实现如下:
tests_unittest.py
1 |
|
Django自带测试模块
打开api
目录下面的tests
文件,编写如下测试代码
tests.py1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from django.test import TestCase
import requests
# Create your tests here.
class UserTest(TestCase):
def setUp(self):
self.base_url='http://127.0.0.1:8000/users'
self.auth=('51zxw','xxxxx')
def test_get_user(self):
r=requests.get(self.base_url+'/1/',auth=self.auth)
result=r.json()
self.assertEqual(result['username'],'51zxw')
self.assertEqual(result['email'],'zxw886@qq.com')
# @unittest.skip('skip add user')
def test_add_user(self):
form_data={'username':'zxw222','email':'zxw668@qq.com','groups':'http://127.0.0.1:8000/groups/2/'}
r=requests.post(self.base_url+'/',data=form_data,auth=self.auth)
result=r.json()
self.assertEqual(result['username'],'zxw222')
# @unittest.skip('skip test_delete_user')
def test_delete_user(self):
r=requests.delete(self.base_url+'/11/',auth=self.auth)
self.assertEqual(r.status_code,204)
def test_update_user(self):
form_data={'email':'2222@163.com'}
r=requests.patch(self.base_url+'/2/',auth=self.auth,data=form_data)
result=r.json()
self.assertEqual(result['email'],'2222@163.com')
def test_user_already_exists(self):
form_data = {'username': 'zxw222', 'email': 'zxw668@qq.com', 'groups': 'http://127.0.0.1:8000/groups/2/'}
r = requests.post(self.base_url + '/', data=form_data, auth=self.auth)
result = r.json()
#预期返回值:{"username":["A user with that username already exists."]}
self.assertEqual(result['username'][0], 'A user with that username already exists.')
def test_no_auth(self):
r=requests.get(self.base_url)
result=r.json()
self.assertEqual(result['detail'],'Authentication credentials were not provided.')
class GroupTest(TestCase):
def setUp(self):
self.base_url='http://127.0.0.1:8000/groups'
self.auth=('51zxw','xxxxxx')
def test_group_developer(self):
r=requests.get(self.base_url+'/3/',auth=self.auth)
result=r.json()
self.assertEqual(result['name'],'Pm')
# @unittest.skip('skip test_add_group')
def test_add_group(self):
form_data={'name':'Leader'}
r=requests.post(self.base_url+'/',auth=self.auth,data=form_data)
result=r.json()
self.assertEqual(result['name'],'Leader')
def test_update_group(self):
form_data={'name':'Boss'}
r=requests.patch(self.base_url+'/6/',auth=self.auth,data=form_data)
result=r.json()
self.assertEqual(result['name'],'Boss')
def test_detele_group(self):
r=requests.delete(self.base_url+'/6/',auth=self.auth)
self.assertEqual(r.status_code,204)
运行方式:打开cmd使用如下命令来运行即可:
1 | D:\django_restful>python manage.py test |
上面命令是默认测试全部的用例,如果想测试部分用例则可以使用如下命令:
测试指定的测试类1
D:\django_restful>python manage.py test api.tests.UserTest
测试具体的某一条具体用例
1 | D:\django_restful>python manage.py test api.tests.UserTest.test_get_user |
视频操作演示
报错相关
- 迁移数据库时没有权限写入
1 | File "C:\Users\jli75\AppData\Local\Programs\Python\Python37\lib\site-packages\MySQLdb\connections.py", line 280, in query |
原因:可能是杀毒软件通过阻止修改frm文件来解决此问题。 通过在杀毒软件威胁防护高级选项中禁用按访问扫描,并杀毒软件设置为忽略这些扩展名来解决此问题
- 迁移数据库时没有清除之前的迁移文件
migrations
1
2
3File "C:\Users\jli75\AppData\Local\Programs\Python\Python37\lib\site-packages\MySQLdb\connections.py", line 280, in query
_mysql.connection.query(self, query)
_mysql_exceptions.OperationalError: (1050, "Table 'djcelery_crontabschedule' already exists")
解决方案:删除migrations
文件夹即可。
- setting配置错误
1 | raise MigrationSchemaMissing("Unable to create the django_migrations table (%s)" % exc) |
解决方案:
Django2.1不再支持MySQL5.5,必须5.6版本以上
可以使用如下命令 查看当前Mysql版本
1 | mysql -V |
参考资料
- https://blog.csdn.net/chenxiaochan/article/details/73716617
- https://www.cnblogs.com/liang1101/p/6266305.html
- https://segmentfault.com/q/1010000009125740/a-1020000009128940
- https://baike.baidu.com/item/django/61531?fr=aladdin
- https://www.jianshu.com/p/dc77f652e7d7
- https://segmentfault.com/q/1010000005685904/