测试开发进阶(二十五)
欢迎关注我的公众号「测试游记」
痛点
代码冗余极其严重,不符合优秀测开风格
数据校验非常麻烦,且可复用性差
编码没有统一的规范,杂乱无章的感觉
写的代码非常多,不够简洁
仅支持json格式的传参,不支持form表单传参
仅能返回json格式的数据,其他类型不支持
列表页视图没有分页,过滤,排序功能
Django REST framework
在Django框架基础上,进行二次开发
用于构建Restful API
简称为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 ModelSerializer
from projects.models import Projects
class ProjectModelSerializer(ModelSerializer):
class Meta:
model = Projects
fields = '__all__'
projects/views.py
中增加
from projects.serializer import ProjectModelSerializer
from rest_framework.viewsets import ModelViewSet
class ProjectViewSet(ModelViewSet):
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer
修改两个路由
# projects/urls.py
from django.urls import path
from projects import views
from rest_framework.routers import DefaultRouter
router = 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.py
from django.contrib import admin
from django.urls import path, include, re_path
urlpatterns = [
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 ProjectSerializer
class 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 OK
Content-Length: 135
Content-Type: application/json
Date: Mon, 14 Oct 2019 16:06:10 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-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)
设置 many
为 True
可以获取多个内容
测试2
$ http :8000/project/
zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/
HTTP/1.1 200 OK
Content-Length: 438
Content-Type: application/json
Date: Mon, 14 Oct 2019 16:15:58 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-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 Created
Content-Length: 162
Content-Type: application/json
Date: Mon, 14 Oct 2019 16:26:19 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-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=True
和 read_only=True
相反,只支持反序列化,不支持序列化。
第二次优化的完整代码
import json
from django.http import JsonResponse, Http404
from projects.models import Projects
from django.views import View
from projects.serializer import ProjectSerializer
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)
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)
上一篇: jekins持续集成