测试开发进阶(二十七)
欢迎关注我的公众号「测试游记」
外键
PrimaryKeyRelatedField
interfaces/serializer.py
中创建序列化器
from rest_framework import serializers
from interfaces.models import Interfaces
class InterfaceModelSerializer(serializers.ModelSerializer):
class Meta:
model = Interfaces
fields = '__all__'
测试
IN[2]: from interfaces.serializer import InterfaceModelSerializer
IN[3]: InterfaceModelSerializer()
Out[4]:
InterfaceModelSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(help_text='项目名称', label='项目名称', max_length=200, validators=[<UniqueValidator(queryset=Interfaces.objects.all())>])
tester = CharField(help_text='测试人员', label='测试人员', max_length=50)
desc = CharField(allow_blank=True, allow_null=True, help_text='简要描述', label='简要描述', required=False, style={'base_template': 'textarea.html'})
project = PrimaryKeyRelatedField(help_text='所属项目', label='所属项目', queryset=Projects.objects.all())
数据库模型中的外键字段默认会生产PrimaryKeyRelatedField序列化器字段
序列化输出的值为外键ID值
序列化输出
from interfaces.models import Interfaces
one_interface = Interfaces.objects.get(id=1)
one_interface
Out[7]: <Interfaces: Interfaces object (1)>
interface_serializer = InterfaceModelSerializer(one_interface)
interface_serializer.data
Out[9]: {'id': 1, 'name': '登录接口', 'tester': 'zx', 'desc': '66', 'project': 1}
字符串关联字段StringRelatedField
重写 project
project = serializers.StringRelatedField(label='所属项目')
from interfaces.models import Interfaces
from interfaces.serializer import InterfaceModelSerializer
one = Interfaces.objects.get(id=1)
one_s = InterfaceModelSerializer(one)
one_s.data
Out[6]: {'id': 1, 'project': '测试游记', 'name': '登录接口', 'tester': 'zx', 'desc': '66'}
StringRelatedField 此字段将被序列化为关联对象字符串表达形式(
__str__
方法返回值)
project = serializers.SlugRelatedField(slug_field='tester')
指定字段数据SlugRelatedField
SlugRelatedField 此字段被序列化为关联对象的指定字段数据
project = serializers.SlugRelatedField(slug_field='name',read_only=True)
from interfaces.serializer import InterfaceModelSerializer
from interfaces.models import Interfaces
one = Interfaces.objects.get(id=1)
one_s = InterfaceModelSerializer(one)
one_s.data
Out[6]: {'id': 1, 'project': '测试游记', 'name': '登录接口', 'tester': 'zx', 'desc': '66'}
关联对象的序列化器
from projects.serializer import ProjectModelSerializer
project = ProjectModelSerializer(label='所属项目', read_only=True)
from interfaces.serializer import InterfaceModelSerializer
from interfaces.models import Interfaces
one = Interfaces.objects.get(id=1)
one_s = InterfaceModelSerializer(one)
one_s.data
Out[6]: {'id': 1, 'project': OrderedDict([('id', 1), ('name', '测试游记'), ('tester', 'zx'), ('programer', 'zhong'), ('publish_app', '公众号'), ('desc', '666')]), 'name': '登录接口', 'tester': 'zx', 'desc': '66'}
反向指定
父表中默认不会生产关联字段(从表),可以手动指定,字段名默认为子表模型类名「小写_set」
projects.serializer.ProjectModelSerializer
中添加
interfaces_set = serializers.StringRelatedField(many=True)
from projects.serializer import ProjectModelSerializer
from projects.models import Projects
p = Projects.objects.get(id=1)
ProjectModelSerializer(p).data
Out[5]: {'id': 1, 'name': '测试游记', 'interfaces_set': ['Interfaces object (1)', 'Interfaces object (2)'], 'tester': 'zx', 'programer': 'zhong', 'publish_app': '公众号', 'desc': '666'}
优化视图-请求
from rest_framework.views import APIView
当视图继承 APIView
之后,请求实例方法中的第二个参数 request
为 Request对象
,是对Django中的 HttpRequest对象
进行的拓展
发送json
http:8000/project/<projects.json
发送form表单
http-f:8000/project/<projects.form
name=测试游记项目&leader=icon&tester=zhongxin&programer=zhong3&publish_app=公众号&desc=无
Request
对Django中的HttpRequest进行拓展
根据请求头中的Content-Type自动进行解析
无论前端发送那种格式数据,都可以以相同的方式读取
request.data
类似于Django中的request.POST和request.FILES
可以对POST,PUT,PATCH的请求体进行解析
支持form表单传参,支持json格式传参
request.query_params
类似Django中的request.GET
获取查询字符串参数
支持Django.request中所有的对象和方法
优化视图-渲染
from rest_framework.response import Response
LearnDjango/settings.py
中添加:
# 指定默认渲染类
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": (
# json渲染器为第一优先级
"rest_framework.renderers.JSONRenderer",
# 可浏览的API渲染为第二优先级
"rest_framework.renderers.BrowsableAPIRenderer",
)
}
修改 projects.views.ProjectDetail#get
def get(self, request, pk):
project = self.get_object(pk)
serializer = ProjectSerializer(instance=project)
return Response(serializer.data)
渲染1
http:8000/project/1/
(LearnDjango) zhongxindeMacBook-Pro:apitest zhongxin$ http :8000/project/1/
HTTP/1.1 200 OK
Allow: GET, PUT, DELETE, HEAD, OPTIONS
Content-Length: 120
Content-Type: application/json
Date: Fri, 18 Oct 2019 13:34:44 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Accept, Origin, Cookie
X-Frame-Options: SAMEORIGIN
{
"desc": "666",
"id": 1,
"leader": "zx_94",
"name": "测试游记",
"programer": "zhong",
"publish_app": "公众号",
"tester": "zx"
}
渲染2
浏览器中输入:http://127.0.0.1:8000/project/1/
Response
参数
data
序列化处理后的数据
一般为serializer.data「python基本数据类型:字典,嵌套字典的列表」
status
状态码,默认200
template_name
模版名称,使用HTMLRenderer渲染时需要指明
headers
用于存放响应头信息的字典
content_type
响应头中的Content-Type
通常此参数无需设置,会自动根据前端所需类型数据来设置该参数
状态码
from rest_framework import status
修改 get
def get(self, request, pk):
project = self.get_object(pk)
serializer = ProjectSerializer(instance=project)
return Response(serializer.data, status=status.HTTP_200_OK)
支持分页,排序的父类GenericAPIView
from rest_framework.generics import GenericAPIView
在视图类中指定过滤引擎
指定需要排序的字段
指定查询集
指定模型序列化器
class ProjectsList(GenericAPIView):
# 1.在视图类中指定过滤引擎
# OrderingFilter排序
filter_backends = [filters.OrderingFilter]
# 2.指定需要排序的字段
ordering_fields = ['name', 'leader']
# 3.指定查询集
queryset = Projects.objects.all()
# 4.指定模型序列化器
serializer_class = ProjectModelSerializer
查看 rest_framework.generics.GenericAPIView#get_queryset
def get_queryset(self):
"""
Get the list of items for this view.
This must be an iterable, and may be a queryset.
Defaults to using `self.queryset`.
This method should always be used rather than accessing `self.queryset`
directly, as `self.queryset` gets evaluated only once, and those results
are cached for all subsequent requests.
You may want to override this if you need to provide different
querysets depending on the incoming request.
(Eg. return a list of items that is specific to the user)
"""
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
queryset = self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
return queryset
所以:project_qs=Projects.objects.all()
和 project_qs=self.get_queryset()
一致
查看 rest_framework.generics.GenericAPIView#get_serializer
和 rest_framework.generics.GenericAPIView#get_serializer_class
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
You may want to override this if you need to provide different
serializations depending on the incoming request.
(Eg. admins get full serialization, others get basic serialization)
"""
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return self.serializer_class
所以:serializer=ProjectSerializer(instance=project_qs,many=True)
和 serializer=self.get_serializer(instance=project_qs,many=True)
一致
本轮优化后的视图
from django.http import Http404
from projects.models import Projects
from projects.serializer import ProjectSerializer, ProjectModelSerializer
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status, filters
class ProjectsList(GenericAPIView):
# 1.在视图类中指定过滤引擎
# OrderingFilter排序
filter_backends = [filters.OrderingFilter]
# 2.指定需要排序的字段
ordering_fields = ['name', 'leader', 'id']
# 3.指定查询集
queryset = Projects.objects.all()
# 4.指定模型序列化器
serializer_class = ProjectModelSerializer
def get(self, reuqest):
project_qs = self.get_queryset()
project_qs = self.filter_queryset(project_qs)
serializer = self.get_serializer(instance=project_qs, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request):
serializer = ProjectSerializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
except Exception as e:
return Response(serializer.errors)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
class ProjectDetail(APIView):
def get_object(self, pk):
try:
return Projects.objects.get(id=pk)
except Projects.DoesNotExist:
raise Http404
def get(self, request, pk):
project = self.get_object(pk)
serializer = ProjectSerializer(instance=project)
return Response(serializer.data, status=status.HTTP_200_OK)
def put(self, request, pk):
project = self.get_object(pk)
serializer = ProjectSerializer(instance=project, data=request.data)
try:
serializer.is_valid(raise_exception=True)
except Exception as e:
return Response(serializer.errors)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def delete(self, request, pk):
project = self.get_object(pk)
project.delete()
return Response({}, status=status.HTTP_204_NO_CONTENT)
正序
zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/?ordering=id
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 711
Content-Type: application/json
Date: Fri, 18 Oct 2019 14:14:51 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Accept, Origin, Cookie
X-Frame-Options: SAMEORIGIN
[
{
"desc": "666",
"id": 1,
"interfaces_set": [
"Interfaces object (1)",
"Interfaces object (2)"
],
"name": "测试游记",
"programer": "zhong",
"publish_app": "公众号",
"tester": "zx"
},
{
"desc": "6666",
"id": 2,
"interfaces_set": [],
"name": "测试游记1",
"programer": "zhong1",
"publish_app": "公众号1",
"tester": "zx1"
},
{
"desc": "666",
"id": 3,
"interfaces_set": [],
"name": "「测试游记」-创建",
"programer": "zx",
"publish_app": "公众号",
"tester": "zx"
},
{
"desc": "「测试游记」",
"id": 7,
"interfaces_set": [],
"name": "1015项目",
"programer": "zhong2",
"publish_app": "公众号2",
"tester": "zx"
},
{
"desc": "无",
"id": 8,
"interfaces_set": [],
"name": "测试游记项目",
"programer": "zhong3",
"publish_app": "公众号",
"tester": "zhongxin"
}
]
zhongxindeMacBook-Pro:~ zhongxin$
倒序
zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/?ordering=-id
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 711
Content-Type: application/json
Date: Fri, 18 Oct 2019 14:15:51 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Accept, Origin, Cookie
X-Frame-Options: SAMEORIGIN
[
{
"desc": "无",
"id": 8,
"interfaces_set": [],
"name": "测试游记项目",
"programer": "zhong3",
"publish_app": "公众号",
"tester": "zhongxin"
},
{
"desc": "「测试游记」",
"id": 7,
"interfaces_set": [],
"name": "1015项目",
"programer": "zhong2",
"publish_app": "公众号2",
"tester": "zx"
},
{
"desc": "666",
"id": 3,
"interfaces_set": [],
"name": "「测试游记」-创建",
"programer": "zx",
"publish_app": "公众号",
"tester": "zx"
},
{
"desc": "6666",
"id": 2,
"interfaces_set": [],
"name": "测试游记1",
"programer": "zhong1",
"publish_app": "公众号1",
"tester": "zx1"
},
{
"desc": "666",
"id": 1,
"interfaces_set": [
"Interfaces object (1)",
"Interfaces object (2)"
],
"name": "测试游记",
"programer": "zhong",
"publish_app": "公众号",
"tester": "zx"
}
]
上一篇: 测试开发进阶(三十九)
下一篇: 简单kaggle房价预测