Django REST framework
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
Django REST framework
Django REST framework 是一个开源的 Django 扩展提供了便捷的 REST API 开发框架拥有以下特性
- 直观的 API web 界面。
- 多种身份认证和权限认证方式的支持。
- 内置了 OAuth1 和 OAuth2 的支持。
- 内置了限流系统。
- 根据 Django ORM 或者其它库自动序列化。
- 丰富的定制层级函数视图、类视图、视图集合到自动生成 API满足各种需要。
- 可扩展性插件丰富。
- 广泛使用文档丰富。
安装与配置
安装命令
pip install djangorestframework
配置 Django REST framework
在settings.py
文件下 INSTALLED_APPS 添加rest_framework
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'sqtp',
'rest_framework', # 配置djangorestframework
]
djangorestframework运行原理
相比于原生django开发的web应用多了一层序列化器(Serializer)序列化器和表单都是基于Field进行字段验证而Field都来自于 rest_framework.fields 模块相当于把django的封装了一层。
序列化与反序列化
序列化Serializer是 Django REST framework 的核心概念提供了数据的验证和渲染功能其工作方式类似于 Django Form
Serializer的作用是实现序列化和反序列化所谓序列化就是将python数据对象转化成方便传输的文本格式如json/xml等。反序列化就是将这个过程反过来。
和models类似序列化通常定义在应用程序下单独文件中serializer.py
如果采用了DRF模式开发django那么model将直接和serializer交互。
模型改造添加元类 Meta
模型的元数据指的是“除了字段外的所有内容”例如排序方式、数据库表名、人类可读的单数或者复数名等等。所有的这些都是非必须的甚至元数据本身对模型也是非必须的。但是有些元数据选项能给予你极大的帮助在实际使用中具有重要的作用是实际应用的‘必须’。
想在模型中增加元数据方法很简单在模型类中添加一个子类名字是固定的 Meta 然后在这个 Meta类 下面增加各种元数据选项或者说设置项。
例如model.py 文件中对Config类添加元类 Meta
# 配置config部分
class Config(models.Model):
name = models.CharField('测试用例名称',max_length=128)
base_url = models.CharField('IP/域名',max_length=256,null=True,blank=True) #可为空或者空白
variables = models.JSONField('变量',null=True)
parameters = models.JSONField('参数',null=True)
export = models.JSONField('用例返回值',null=True)
verify = models.BooleanField('https校验',default=False)
def __str__(self):
return self.name
# 以 测试用例名称 对外展示
# 模型元类的作用提供额外的信息比如模型对应的表名
class Meta:
db_table = 'Config' # 如果不设置默认的名称是 app名_模型名
ordering = ['id'] # 根据id排序默认为顺序排序
# ordering = ['-id'] # 根据id排序倒序排序
注意如果已经在数据库中进行了迁移生成过表此时通过 db_table
设置表名会报错可以新建一个测试数据库或者将原来数据库里的表删除。
执行命令python manage.py makemigrations
和python manage.py migrate
可以看到数据库中表名为Config
创建序列化类
开发 Web API的第一件事是为 Web API 提供一种将代码片段实例序列化和反序列化为诸如 json 之类的表示形式的方式。 在 sqtp的目录下创建一个名为 serializers.py
文件并添加以下内容
from rest_framework import serializers
from sqtp.models import Config,Case,Step,Request
# 命名规范模型名+Serializer
class RequestSerializer(serializers.Serializer): # 继承 Serializer
step = serializers.RelatedField(queryset=Step.objects.all(),allow_null=True)
# method可选字段二维元组
method_choices = (
(0, 'GET'), # 参数1保存在数据库中的值参数2对外显示的值
(1, 'POST'),
(2, 'PUT'),
(3, 'DELETE'),
)
method = serializers.ChoiceField(choices=method_choices, default=0)
url = serializers.CharField()
params = serializers.JSONField(allow_null=True)
headers = serializers.JSONField(allow_null=True)
cookies = serializers.JSONField(allow_null=True)
data = serializers.JSONField(allow_null=True)
json = serializers.JSONField(allow_null=True)
# 重写创建和修改方法
def create(self, validated_data):
'''
validated_data:经过校验之后的数据字典类型
'''
return Request.objects.create(**validated_data) # 对字典进行捷豹动作相当于name=xx,age=yyy
def update(self, instance, validated_data):
'''
instance:被修改的数据对象/实例
validated_data:经过校验之后的入参数据字典类型
'''
# dict 的 get(key,默认值) 如果有参数传来就取key的value如果没有就取原来的默认值覆盖
instance.step = validated_data.get('step',instance.step)
instance.method = validated_data.get('method',instance.method)
instance.url = validated_data.get('url',instance.url)
instance.params = validated_data.get('params',instance.params)
instance.headers = validated_data.get('headers',instance.headers)
instance.cookies = validated_data.get('cookies',instance.cookies)
instance.data = validated_data.get('data',instance.data)
instance.json = validated_data.get('json',instance.json)
序列化器的作用是 转化 json为模型对象数据或者转化模型对象数据为json序列化器是针对数据模型一个序列化器对应一个模型。
序列化器类的第一部分定义了序列化/反序列化的字段。 create()
和 update()
方法定义了在调用 serializer.save()
时如何创建和修改完整的实例
使用序列化类
在sqtp
应用app目录下新建测试文件/test_serializers.py
序列化
# Create your tests here.
from django.test import TestCase
from sqtp.models import Case, Config, Step, Request
from sqtp.serializers import RequestSerializer
# 导入序列化和反序列化器
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
class TestRequestSerializer(TestCase):
req1=Request.objects.create(method=0,url='/api/teacher/',data={"name":"小王老师","courses":"英语","address":"广东深圳"})
req1_serializer = RequestSerializer(req1)
print('===================序列化:数据对象-->>python原生数据类型====================')
print(req1_serializer)
print('*****************************************************')
print('数据内容{}'.format(req1_serializer.data)) # 序列化数据存储在序列化对象的data属性中
print('=================== 序列化:python原生数据类型-->>json ====================')
content = JSONRenderer().render(req1_serializer.data)
print(content)
执行python manage.py test sqtp.test_serializers
命令进行测试
===================序列化:数据对象-->>python原生数据类型====================
RequestSerializer(<Request: /api/teacher/>):
step = RelatedField(allow_null=True, queryset=<QuerySet []>)
method = ChoiceField(choices=((0, 'GET'), (1, 'POST'), (2, 'PUT'), (3, 'DELETE')), default=0)
url = CharField()
params = JSONField(allow_null=True)
headers = JSONField(allow_null=True)
cookies = JSONField(allow_null=True)
data = JSONField(allow_null=True)
json = JSONField(allow_null=True)
*****************************************************
数据内容{'step': None, 'method': 0, 'url': '/api/teacher/', 'params': None, 'headers': None, 'cookies': None, 'data': {'name': '小王老师', 'courses': '英语', 'address': '广东深圳'}, 'json': None}
=================== 序列化:python原生数据类型-->>json ====================
b'{"step":null,"method":0,"url":"/api/teacher/","params":null,"headers":null,"cookies":null,"data":{"name":"\xe5\xb0\x8f\xe7\x8e\x8b\xe8\x80\x81\xe5\xb8\x88","courses":"\xe8\x8b\xb1\xe8\xaf\xad","address":"\xe5\xb9\xbf\xe4\xb8\x9c\x
e6\xb7\xb1\xe5\x9c\xb3"},"json":null}'
可以发现python原生数据类型序列化成json后是这种可以直接在网络中传输的数据流ASCII 码\xe5\xb0\x8f\xe7\x8e\x8b\xe8\x80\x81\xe5\xb8\x88
反序列化
# Create your tests here.
from django.test import TestCase
from sqtp.models import Case, Config, Step, Request
from sqtp.serializers import RequestSerializer
# 导入序列化和反序列化器
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
class TestRequestSerializer(TestCase):
req1=Request.objects.create(method=0,url='/api/teacher/',data={"name":"小王老师","courses":"英语","address":"广东深圳"})
req1_serializer = RequestSerializer(req1)
print('===================序列化:数据对象-->>python原生数据类型====================')
print(req1_serializer)
print('*****************************************************')
print('数据内容{}'.format(req1_serializer.data)) # 序列化数据存储在序列化对象的data属性中
print('=================== 序列化:python原生数据类型-->>jsonstream流 ====================')
content = JSONRenderer().render(req1_serializer.data)
print(content) #数据流ASCII 码
print('===================反序列化:将流stream解析为Python原生数据类型===================')
import io
stream = io.BytesIO(content) # 构建一个stream流
data = JSONParser().parse(stream) # 转成python原生数据类型
print('data数据内容:{}'.format(data))
print('===================反序列化:将Python原生数据类型恢复成正常的对象实例===================')
serializer = RequestSerializer(data=data) # 构建序列化器
print('校验数据是否合法{}'.format(serializer.is_valid()))
print('查看校验之后数据{}'.format(serializer.validated_data))
if serializer.is_valid():
serializer.save() # 保存数据
print('===================序列化查询结果集querysets===================')
serializer = RequestSerializer(Request.objects.all(),many=True)
print(serializer.data)
反序列化是类似的将流stream解析为Python原生数据类型后再恢复成正常的对象实例
===================反序列化:将流stream解析为Python原生数据类型===================
data数据内容:{'step': None, 'method': 0, 'url': '/api/teacher/', 'params': None, 'headers': None, 'cookies': None, 'data': {'name': '小王老师', 'courses': '英语', 'address': '广东深圳'}, 'json': None}
===================反序列化:将Python原生数据类型恢复成正常的对象实例===================
校验数据是否合法True
查看校验之后数据OrderedDict([('step', None), ('method', 0), ('url', '/api/teacher/'), ('params', None), ('headers', None), ('cookies', None), ('data', {'name': '小王老师', 'courses': '英语', 'address': '广东深圳'}), ('json', None)
])
除了序列化模型实例序列化器还可以序列化查询结果集querysets返回完整结果集只需要为serializer添加一个 many=True
标志
改进序列化器
以上是序列化器的工作过程在实际的项目中不会写这么繁复的代码可以用 ModelSerializer 代替 Serializer 类作为自定义序列化器的父类减少重复代码的编写。
打开 sqtp的目录下的 serializers.py
文件,使用 ModelSerializer 重构序列化类
from rest_framework import serializers
from sqtp.models import Config,Case,Step,Request
# 命名规范模型名+Serializer
class RequestSerializer(serializers.ModelSerializer): # 继承 Serializer
class Meta:
model = Request # 指定序列化器对应的模型
# fields = ['step','method','url','params','headers'] # 指定序列化模型中的字段
fields = '__all__' # 序列化所有字段
ModelSerializer 类并不会做任何特别神奇的事情它们只是创建序列化器类的快捷方式
-
一组自动确定的字段。
-
默认简单实现的 create() 和 update() 方法
相应的字段已经隐含在类中了可在测试文件/test_serializers.py
测试类中添加代码查看序列化器的内部结构
print('===================打印序列化器类实例的结构(representation)查看它的所有字段===================')
print(repr(serializer))
输出内容
===================打印序列化器类实例的结构(representation)查看它的所有字段===================
RequestSerializer(<QuerySet [<Request: /api/teacher/>, <Request: /mgr/student/>, <Request: /api/teacher/>, <Request: /mgr/student/>, <Request: /api/teacher/>, <Request: /mgr/student/>, <Request: /api/teacher/>, <Request: /mgr/studen
t/>, <Request: /api/teacher/>, <Request: /api/teacher/>, <Request: /mgr/student/>, <Request: /api/teacher/>, <Request: /api/teacher/>, <Request: /mgr/student/>, <Request: /api/teacher/>, <Request: /api/teacher/>, <Request: /mgr/stud
ent/>, <Request: /api/teacher/>, <Request: /api/teacher/>, <Request: /mgr/student/>, '...(remaining elements truncated)...']>, many=True):
id = IntegerField(label='ID', read_only=True)
method = ChoiceField(choices=((0, 'GET'), (1, 'POST'), (2, 'PUT'), (3, 'DELETE')), label='请求方法', required=False, validators=[<django.core.validators.MinValueValidator object>, <django.core.validators.MaxValueValidator object
>])
url = CharField(label='请求路径', max_length=1000, required=False)
params = JSONField(allow_null=True, decoder=None, encoder=None, label='Url参数', required=False, style={'base_template': 'textarea.html'})
headers = JSONField(allow_null=True, decoder=None, encoder=None, label='请求头', required=False, style={'base_template': 'textarea.html'})
cookies = JSONField(allow_null=True, decoder=None, encoder=None, required=False, style={'base_template': 'textarea.html'})
data = JSONField(allow_null=True, decoder=None, encoder=None, label='Data参数', required=False, style={'base_template': 'textarea.html'})
json = JSONField(allow_null=True, decoder=None, encoder=None, label='Json参数', required=False, style={'base_template': 'textarea.html'})
step = PrimaryKeyRelatedField(allow_null=True, queryset=Step.objects.all(), required=False, validators=[<UniqueValidator(queryset=Request.objects.all())>])
DRF视图编写
常规Django视图编写
序列化器最终的作用是为视图提供转化后的数据可使用Serializer类编写一些 API视图。这里没有使用任何djangorestframework 框架的其他功能只是将视图作为常规Django视图编写。
编辑在sqtp
应用app目录下的views.py
文件导入以下库并编写一个视图可以返回所有的请求数据
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt # 跨站攻击防护接口白名单处理
from rest_framework.parsers import JSONParser # 序列化
from sqtp.models import Request # 模型
from sqtp.serializers import RequestSerializer # 自定义的序列化类
def request_list(request):
if request.method == 'GET':
# 构建序列化器返回完整结果集--针对当前数据模型的所有数据
serializer = RequestSerializer(Request.objects.all(),many=True)
# 返回json格式响应
return JsonResponse(data=serializer.data,safe=False) #safe=False是为了支持字典类型以外的python对象转json例如列表[]
在sqtp
应用app目录下新建urls.py
文件写入路由
from django.urls import path
from sqtp import views as sqtp_view
urlpatterns = [
path('requests/',sqtp_view.request_list)
]
在 AutoTpsite
项目目录下的 urls.py
文件下引入子路由
from django.contrib import admin
from django.urls import path,include
from sqtp import urls as sqtp_urls
urlpatterns = [
path('admin/', admin.site.urls),
path('',include(sqtp_urls)),
]
执行命令python manage.py runserver 0.0.0.0:8888
启动项目在浏览器中输入http://127.0.0.1:8888/requests/
可以发现返回了json数据
[{"id": 38, "method": 0, "url": "/api/teacher/", "params": null, "headers": null, "cookies": null, "data": {"name": "\u5c0f\u738b\u8001\u5e08", "courses": "\u82f1\u8bed", "address": "\u5e7f\u4e1c\u6df1\u5733"}, "json": null, "step": null}, {"id": 39, "method": 0, "url": "/api/teacher/", "params": null, "headers": null, "cookies": null, "data": {"name": "\u5c0f\u738b\u8001\u5e08", "courses": "\u82f1\u8bed", "address": "\u5e7f\u4e1c\u6df1\u5733"}, "json": null, "step": null}]
视图装饰器api_view
接口开发本质上是处理请求和响应包括了处理请求参数判断请求方法处理响应字段响应码等本身是个枯燥的活DRF框架提供自动处理这些枯燥工具的方法函数视图装饰器@api_view
视图装饰器api_view作用
-
确保在视图中接收到Request实例并将上下文添加到Response以便可以执行内容协商
-
装饰器还提供了诸如在适当时候返回
405 Method Not Allowed
响应并处理在使用格式错误的输入来访问request.data
时发生的任何ParseError
异常
返回所有数据
修改sqtp
应用app目录下的views.py
文件
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt # 跨站攻击防护接口白名单处理
from rest_framework.parsers import JSONParser # 序列化
from rest_framework.response import Response
from sqtp.models import Request # 模型
from sqtp.serializers import RequestSerializer # 自定义的序列化类
from rest_framework.decorators import api_view
@api_view(['GET']) # 列表中是允许的请求方法
def request_list(request):
serializer = RequestSerializer(Request.objects.all(), many=True)
return Response(serializer.data) # 使用DRF框架的响应对象自动分配返回格式
执行命令python manage.py runserver 0.0.0.0:8888
启动项目在浏览器中输入http://127.0.0.1:8888/requests/
可以发现页面返回的json数据展示多了一些内容是因为DRF框架对Response的内容加了一层封装把数据渲染到一个内部的模板上。
返回单条数据
以上是查询所有数据再开发一个接口查询单个数据
在sqtp
应用app目录下的views.py
文件下新增视图函数
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt # 跨站攻击防护接口白名单处理
from rest_framework import status
from rest_framework.parsers import JSONParser # 序列化
from rest_framework.response import Response
from sqtp.models import Request # 模型
from sqtp.serializers import RequestSerializer # 自定义的序列化类
from rest_framework.decorators import api_view
@api_view(['GET']) # 列表中是允许的请求方法
def request_list(request):
serializer = RequestSerializer(Request.objects.all(), many=True)
return Response(serializer.data) # 使用DRF框架的响应对象自动分配返回格式
@api_view(['GET'])
def request_detail(request,_id):
try:
req_obj = Request.objects.get(id=_id)
# 序列化将数据对象转化为json格式
serializer = RequestSerializer(req_obj)
return Response(data=serializer.data)
except Exception:
return Response(status=status.HTTP_404_NOT_FOUND) # 返回错误状态码
在sqtp
应用app目录下的urls.py
文件新增路由
from django.urls import path
from sqtp import views as sqtp_view
urlpatterns = [
path('requests/',sqtp_view.request_list),
path('requests/<int:_id>',sqtp_view.request_detail),
]
执行命令python manage.py runserver 0.0.0.0:8888
启动项目在浏览器中输入http://127.0.0.1:8888/requests/1
页面就返回单个数据输入数据库不存在的id页面则返回404
返回json格式的数据
在浏览器中输入http://127.0.0.1:8888/requests/1
请求页面返回的是html格式的内容
有这么一个骚操作在浏览器中输入请求的后缀http://127.0.0.1:8888/requests/38.json
请求页面可返回json格式的内容
在sqtp
应用app目录下的views.py
文件下修改视图函数加上参数format
@api_view(['GET']) # 列表中是允许的请求方法
def request_list(request,format=None):
serializer = RequestSerializer(Request.objects.all(), many=True)
return Response(serializer.data) # 使用DRF框架的响应对象自动分配返回格式
@api_view(['GET'])
def request_detail(request,_id,format=None):
try:
req_obj = Request.objects.get(id=_id)
# 序列化将数据对象转化为json格式
serializer = RequestSerializer(req_obj)
return Response(data=serializer.data)
except Exception:
return Response(status=status.HTTP_404_NOT_FOUND) # 返回错误状态码
对sqtp
应用app目录下的urls.py
文件的路由信息进行补充DRF框架提供format_suffix_patterns
方法重写url信息对请求的url进行进一步处理
from django.urls import path
from sqtp import views as sqtp_view
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path('requests/',sqtp_view.request_list),
path('requests/<int:_id>',sqtp_view.request_detail),
]
urlpatterns = format_suffix_patterns(urlpatterns) # 重写url
页面返回的就是json格式的内容