测试开发进阶(二十八)

测试开发进阶(二十八)

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

如果前端请求头中没有指定Accept 默认返回json格式的数据

text/html

1
$ http -v :8000/project/1/ Accept:text/html

返回页面

application/json

1
$ http -v :8000/project/1/ Accept:application/json

![返回json](../../../Library/Application Support/typora-user-images/image-20191022214337309.png)

使用GenericAPIView重写ProjectDetail

1
2
3
4
5
6
7
8
class ProjectDetail(GenericAPIView):
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer

def get(self, request, pk):
project = self.get_object()
serializer = self.get_serializer(instance=project)
return Response(serializer.data, status=status.HTTP_200_OK)

GenericAPIView

从源码中可以看到GenericAPIView中实现了get_object方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def get_object(self):
"""
Returns the object the view is displaying.

You may want to override this if you need to provide non-standard
queryset lookups. Eg if objects are referenced using multiple
keyword arguments in the url conf.
"""
queryset = self.filter_queryset(self.get_queryset())

# Perform the lookup filtering.
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field

assert lookup_url_kwarg in self.kwargs, (
'Expected view %s to be called with a URL keyword argument '
'named "%s". Fix your URL conf, or set the `.lookup_field` '
'attribute on the view correctly.' %
(self.__class__.__name__, lookup_url_kwarg)
)

filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
obj = get_object_or_404(queryset, **filter_kwargs)

# May raise a permission denied
self.check_object_permissions(self.request, obj)

return obj

查看self.lookup_field可以找到

lookup_field = 'pk'

进入get_object_or_404可以看到一个解包,这样就拿到了查询集中id=1的内容

解包

所以使用lookup_field类属性,可以修改传入的内容命名

  • 使用get_serializer获取序列化器

全局指定排序

LearnDjango/settings.py中添加

1
2
3
4
5
6
7
8
9
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": (
# json渲染器为第一优先级
"rest_framework.renderers.JSONRenderer",
# 可浏览的API渲染为第二优先级
"rest_framework.renderers.BrowsableAPIRenderer",
),
'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.OrderingFilter']
}

过滤

安装

1
$ pip install django-filter

使用

添加django_filtersAPP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'django_filters',
# 注册子应用
# 子应用名.apps.子应用名首字母大写Config
'projects.apps.ProjectsConfig',
'interfaces.apps.InterfacesConfig',
'corsheaders',
]

projects/views.py导入

1
from django_filters.rest_framework import DjangoFilterBackend

projects.views.ProjectsList添加

1
2
3
4
# 5.在类视图中指定过滤引擎
filter_backends = [DjangoFilterBackend]
# 6.指定过滤的字段
filterset_fields = ['name', 'leader']

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ http :8000/project/ name=='测试游记1'
zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/ name=='测试游记1'
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 130
Content-Type: application/json
Date: Tue, 22 Oct 2019 14:19:31 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Accept, Origin, Cookie
X-Frame-Options: SAMEORIGIN

[
{
"desc": "6666",
"id": 2,
"interfaces_set": [],
"name": "测试游记1",
"programer": "zhong1",
"publish_app": "公众号1",
"tester": "zx1"
}
]

过滤

在全局指定

1
2
3
4
5
6
7
8
9
10
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": (
# json渲染器为第一优先级
"rest_framework.renderers.JSONRenderer",
# 可浏览的API渲染为第二优先级
"rest_framework.renderers.BrowsableAPIRenderer",
),
'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.OrderingFilter',
'django_filters.rest_framework.DjangoFilterBackend']
}

分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": (
# json渲染器为第一优先级
"rest_framework.renderers.JSONRenderer",
# 可浏览的API渲染为第二优先级
"rest_framework.renderers.BrowsableAPIRenderer",
),
'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.OrderingFilter',
'django_filters.rest_framework.DjangoFilterBackend'],
# 在全局指定分页的引擎
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
# 同时必须指定每页显示的条数
'PAGE_SIZE': 3,
}

修改projects.views.ProjectsList#get

1
2
3
4
5
6
7
8
9
10
11
12
def get(self, reuqest):
# 使用get_queryset获取查询集
project_qs = self.get_queryset()
# 使用filter_queryset方法过滤查询
project_qs = self.filter_queryset(project_qs)
# 使用paginate_queryset进行分页,然后返回分页之后的查询集
page = self.paginate_queryset(project_qs)
if page is not None:
serializer = self.get_serializer(instance=page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(instance=project_qs, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)

分页后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 520
Content-Type: application/json
Date: Tue, 22 Oct 2019 14:41:54 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Accept, Origin, Cookie
X-Frame-Options: SAMEORIGIN

{
"count": 5,
"next": "http://localhost:8000/project/?page=2",
"previous": null,
"results": [
{
"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"
}
]
}

zhongxindeMacBook-Pro:~ zhongxin$

分页后

自定义分页

utils.pagination.PageNumberPaginationManual新写一个类继承于PageNumberPagination

1
2
3
4
5
6
7
from rest_framework.pagination import PageNumberPagination


class PageNumberPaginationManual(PageNumberPagination):
page_query_param = 'p' # url中查询关键字从page修改为p
page_size = 2 # 每页显示的条数为2
max_page_size = 50 # 分页的最大的page_size

image-20191022224552266

在某个类中指定分页

添加

1
pagination_class = PageNumberPaginationManual

再次优化

借鉴python3.7/site-packages/rest_framework/mixins.py

查看rest_framework.mixins.ListModelMixin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())

page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)

serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

发现和projects.views.ProjectsList#get一样

修改get

1
2
3
4
5
from rest_framework import mixins
class ProjectsList(mixins.ListModelMixin, GenericAPIView):

def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)

全部优化后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from projects.models import Projects
from projects.serializer import ProjectModelSerializer
from rest_framework.generics import GenericAPIView
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import mixins


class ProjectsList(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
ordering_fields = ['name', 'leader']
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['name', 'leader', 'tester']

def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)

def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)


class ProjectDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer

def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)

def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)

def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
您的支持将鼓励我继续创作!