专栏首页测试游记测试开发进阶(二十五)

测试开发进阶(二十五)

痛点

  • 代码冗余极其严重,不符合优秀测开风格
  • 数据校验非常麻烦,且可复用性差
  • 编码没有统一的规范,杂乱无章的感觉
  • 写的代码非常多,不够简洁
  • 仅支持json格式的传参,不支持form表单传参
  • 仅能返回json格式的数据,其他类型不支持
  • 列表页视图没有分页,过滤,排序功能

Django REST framework

  1. 在Django框架基础上,进行二次开发
  2. 用于构建Restful API
  3. 简称为DRF框架或REST freamwork框架

特性

  • 提供了强大的Serializer序列化器,可以高效地进行序列化与反序列化操作
  • 提供了丰富的类视图,Mixin扩展类,ViewSet视图集
  • 提供了直观的Web API界面
  • 多种身份认证和权限认证
  • 强大的排序,过滤,分页,搜索,限流等功能
  • 可扩展性,插件丰富

安装

$ pip install djangorestframework

配置

LearnDjango/settings.py中添加 'rest_framework'

INSTALLED_APPS = [    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',    'rest_framework',    'projects.apps.ProjectsConfig',    'interfaces.apps.InterfacesConfig',    'corsheaders',]

快速创建实例

新建 projects/serializer.py

from rest_framework.serializers import ModelSerializerfrom projects.models import Projectsclass ProjectModelSerializer(ModelSerializer):    class Meta:        model = Projects        fields = '__all__'

projects/views.py中增加

from projects.serializer import ProjectModelSerializerfrom rest_framework.viewsets import ModelViewSetclass ProjectViewSet(ModelViewSet):    queryset = Projects.objects.all()    serializer_class = ProjectModelSerializer

修改两个路由

# projects/urls.pyfrom django.urls import pathfrom projects import viewsfrom rest_framework.routers import DefaultRouterrouter = DefaultRouter()router.register('projects', views.ProjectViewSet)urlpatterns = [    path('project/', views.ProjectsList.as_view()),    path('project/<int:pk>/', views.ProjectDetail.as_view()),]urlpatterns += router.urls# LearnDjango/urls.pyfrom django.contrib import adminfrom django.urls import path, include, re_pathurlpatterns = [    path('admin/', admin.site.urls),    path('interfaces/', include('interfaces.urls')),    path('', include('projects.urls')),    path('api/', include('rest_framework.urls')),]

查看结果

逐步优化之前的代码

之前「快速创建实例」部分为演示最终效果,现在先恢复到原有状态

创建序列化

创建 projects/serializer.py

需要输出哪些字段,那么在序列化器中就定义哪些字段

from rest_framework import serializers# 1.继承Serializer类或者子类class ProjectSerializer(serializers.Serializer):    """    创建项目序列化器类    """    # label选项相当于verbose_name    # help_text相当于帮助信息    #    id = serializers.IntegerField(label='ID')    name = serializers.CharField(label='项目名称', max_length=200, help_text='项目名称')    tester = serializers.CharField(label='测试人员', max_length=50, help_text='测试人员')    programer = serializers.CharField(label='开发人员', max_length=50, help_text='开发人员')    publish_app = serializers.CharField(label='发布应用', max_length=50, help_text='发布应用')    # allow_null相当于模型类中的null    # allow_blank相当于模型类中的blank    desc = serializers.CharField(label='简要描述', help_text='简要描述', allow_blank=True, default='', allow_null=True)

查询单个内容

修改 projects.views.ProjectDetail#get

1.通过模型类对象(或者查询集),传给instance 就可以进行序列化操作 2.通过序列化器ProjectSerializer对象的data属性,就可以获取转化后的字典

from projects.serializer import ProjectSerializerclass ProjectDetail(View):    def get(self, request, pk):        project = Projects.objects.get(id=pk)        serializer = ProjectSerializer(instance=project)        return JsonResponse(serializer.data)

测试1

$ http :8000/project/1/zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/1/HTTP/1.1 200 OKContent-Length: 135Content-Type: application/jsonDate: Mon, 14 Oct 2019 16:06:10 GMTServer: WSGIServer/0.2 CPython/3.7.1Vary: OriginX-Frame-Options: SAMEORIGIN{    "desc": "666",    "id": 1,    "name": "测试游记",    "programer": "zhong",    "publish_app": "公众号",    "tester": "zx"}

查询多个内容

class ProjectsList(View):    def get(self, reuqest):        project_qs = Projects.objects.all()        serializer = ProjectSerializer(instance=project_qs, many=True)        return JsonResponse(serializer.data, safe=False)

设置 manyTrue可以获取多个内容

测试2

$ http :8000/project/zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/HTTP/1.1 200 OKContent-Length: 438Content-Type: application/jsonDate: Mon, 14 Oct 2019 16:15:58 GMTServer: WSGIServer/0.2 CPython/3.7.1Vary: OriginX-Frame-Options: SAMEORIGIN[    {        "desc": "666",        "id": 1,        "name": "测试游记",        "programer": "zhong",        "publish_app": "公众号",        "tester": "zx"    },    {        "desc": "6666",        "id": 2,        "name": "测试游记1",        "programer": "zhong1",        "publish_app": "公众号1",        "tester": "zx1"    },    {        "desc": "666",        "id": 3,        "name": "「测试游记」-创建",        "programer": "zx",        "publish_app": "公众号",        "tester": "zx"    }]

反序列化部分优化

调用序列化器对象的is_valid方法,开始校验前端参数

  • 校验成功返回True
  • 校验失败返回False

serializer.is_valid(raise_exception=True) raise_exception=True校验失败会抛出异常 当调用 is_valid方法后,才可以调用 errors属性,获取校验的错误提示「字典格式」

class ProjectsList(View):    def post(self, request):        """        新建项目        """        json_data = request.body.decode('utf8')        python_data = json.loads(json_data, encoding='utf8')        serializer = ProjectSerializer(data=python_data)        # 校验前端输入的数据        try:            serializer.is_valid(raise_exception=True)        except Exception as e:            return JsonResponse(serializer.errors)        project = Projects.objects.create(**serializer.validated_data)        serializer = ProjectSerializer(instance=project)        return JsonResponse(serializer.data, status=201)

测试3

$ http :8000/project/ name=1015项目 tester=zx programer=zhong2  publish_app=公众号2 desc=「测试游记」zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/ name=1015项目 tester=zx programer=zhong2  publish_app=公众号2 desc=「测试游记」HTTP/1.1 201 CreatedContent-Length: 162Content-Type: application/jsonDate: Mon, 14 Oct 2019 16:26:19 GMTServer: WSGIServer/0.2 CPython/3.7.1Vary: OriginX-Frame-Options: SAMEORIGIN{    "desc": "「测试游记」",    "id": 7,    "name": "1015项目",    "programer": "zhong2",    "publish_app": "公众号2",    "tester": "zx"}

测试4

再次发送相同内容

$ http :8000/project/ name=1015项目 tester=zx programer=zhong2  publish_app=公众号2 desc=「测试游记」

上面这个错误有些不合理。

修改 projects.serializer.ProjectSerializer中的

id = serializers.IntegerField(label='ID', read_only=True)

增加 read_only=True,指定该字段只能进行序列化输出「只读」,不进行反序列化。其他字段默认即可以进行序列化输出,也可以反序列化输出

write_only=Trueread_only=True相反,只支持反序列化,不支持序列化。

第二次优化的完整代码

import jsonfrom django.http import JsonResponse, Http404from projects.models import Projectsfrom django.views import Viewfrom projects.serializer import ProjectSerializerclass ProjectsList(View):    def get(self, reuqest):        project_qs = Projects.objects.all()        serializer = ProjectSerializer(instance=project_qs, many=True)        return JsonResponse(serializer.data, safe=False)    def post(self, request):        """        新建项目        """        json_data = request.body.decode('utf8')        python_data = json.loads(json_data, encoding='utf8')        serializer = ProjectSerializer(data=python_data)        # 校验前端输入的数据        # 调用序列化器对象的is_valid方法,开始校验前端参数        # serializer.is_valid(raise_exception=True) raise_exception=True校验失败会抛出异常        try:            serializer.is_valid(raise_exception=True)        except Exception as e:            return JsonResponse(serializer.errors)        project = Projects.objects.create(**serializer.validated_data)        serializer = ProjectSerializer(instance=project)        return JsonResponse(serializer.data, status=201)class ProjectDetail(View):    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 JsonResponse(serializer.data)    def put(self, request, pk):        project = self.get_object(pk)        json_data = request.body.decode('utf8')        python_data = json.loads(json_data, encoding='utf8')        serializer = ProjectSerializer(data=python_data)        try:            serializer.is_valid(raise_exception=True)        except Exception as e:            return JsonResponse(serializer.errors)        project.name = serializer.validated_data['name']        project.leader = serializer.validated_data['leader']        project.tester = serializer.validated_data['tester']        project.programer = serializer.validated_data['programer']        project.publish_app = serializer.validated_data['publish_app']        project.desc = serializer.validated_data['desc']        project.save()        serializer = ProjectSerializer(instance=project)        return JsonResponse(serializer.data, status=201)    def delete(self, request, pk):        project = self.get_object(pk)        project.delete()        return JsonResponse({}, safe=True, status=204)

本文分享自微信公众号 - 测试游记(zx94_11)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python 字符串删除

    用户5760343
  • python 字符串拼接

    用户5760343
  • LeetCode 706:设计哈希映射 Design HashMap

    Design a HashMap without using any built-in hash table libraries.

    爱写bug
  • lambda表达式与函数式编程

    lambda表达式是java支持函数式编程的实现方案,很多高级语言已经支持lambda表达式,像python、javascript等。lambda表达式使代码更...

    搬砖俱乐部
  • 用Python做个微信自动回复机器人

    今天我们来玩转一下微信,微信有关的第三方框架很多,比如wxpy,wxBot等。今天要使用的是其中著名的itchat Python模块来做两件有趣的事情。

    sergiojune
  • python 换行匹配

    用户5760343
  • python 字符串对齐和填充

    用户5760343
  • 30段极简Python代码:这些小技巧你都Get了么

    Python 是机器学习最广泛采用的编程语言,它最重要的优势在于编程的易用性。如果读者对基本的 Python 语法已经有一些了解,那么这篇文章可能会给你一些启发...

    机器之心
  • Python技术周刊:第 13 期

    1、揭开Python args和kwargs的神秘面纱[1] 学习如何在Python中使用args和kwargs来为你的函数添加更多灵活性。

    逍遥散人2019
  • python 贪婪匹配 非贪婪匹配

    用户5760343

扫码关注云+社区

领取腾讯云代金券