测试开发进阶(二十七)

欢迎关注我的公众号「测试游记」

外键

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}

640?wx_fmt=jpeg

640?wx_fmt=jpeg

字符串关联字段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'}

640?wx_fmt=jpeg

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'}

640?wx_fmt=jpeg

关联对象的序列化器

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'}

640?wx_fmt=jpeg

反向指定

父表中默认不会生产关联字段(从表),可以手动指定,字段名默认为子表模型类名「小写_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'}

640?wx_fmt=jpeg

优化视图-请求

from rest_framework.views import APIView

当视图继承 APIView之后,请求实例方法中的第二个参数 requestRequest对象,是对Django中的 HttpRequest对象进行的拓展

640?wx_fmt=jpeg

发送json

http:8000/project/<projects.json

640?wx_fmt=jpeg

发送form表单

http-f:8000/project/<projects.form

name=测试游记项目&leader=icon&tester=zhongxin&programer=zhong3&publish_app=公众号&desc=无

640?wx_fmt=jpeg

640?wx_fmt=jpeg

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"	
}

640?wx_fmt=jpeg

渲染2

浏览器中输入:http://127.0.0.1:8000/project/1/

640?wx_fmt=jpeg

Response

参数

  • data

序列化处理后的数据

一般为serializer.data「python基本数据类型:字典,嵌套字典的列表」

  • status

状态码,默认200

  • template_name

模版名称,使用HTMLRenderer渲染时需要指明

  • headers

用于存放响应头信息的字典

  • content_type

响应头中的Content-Type

通常此参数无需设置,会自动根据前端所需类型数据来设置该参数

状态码

from rest_framework import status

640?wx_fmt=jpeg

修改 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
  1. 在视图类中指定过滤引擎

  2. 指定需要排序的字段

  3. 指定查询集

  4. 指定模型序列化器

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_serializerrest_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)

正序

640?wx_fmt=jpeg

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"	
    }	
]

640?wx_fmt=jpeg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值