欢迎关注我的公众号「测试游记」
如果前端请求头中没有指定Accept 默认返回json格式的数据
text/html
$ http -v :8000/project/1/ Accept:text/html
application/json
$ http -v :8000/project/1/ Accept:application/json
!返回json
使用GenericAPIView重写ProjectDetail
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
中实现了 get_object
方法
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
中添加
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": (
# json渲染器为第一优先级
"rest_framework.renderers.JSONRenderer",
# 可浏览的API渲染为第二优先级
"rest_framework.renderers.BrowsableAPIRenderer",
),
'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.OrderingFilter']
}
过滤
安装
$ pip install django-filter
使用
添加 django_filters
APP
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
导入
from django_filters.rest_framework import DjangoFilterBackend
在 projects.views.ProjectsList
添加
# 5.在类视图中指定过滤引擎
filter_backends = [DjangoFilterBackend]
# 6.指定过滤的字段
filterset_fields = ['name', 'leader']
查询
$ 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"
}
]
在全局指定
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']
}
分页
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
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)
分页后
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
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
在某个类中指定分页
添加
pagination_class = PageNumberPaginationManual
再次优化
借鉴 python3.7/site-packages/rest_framework/mixins.py
查看 rest_framework.mixins.ListModelMixin
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
from rest_framework import mixins
class ProjectsList(mixins.ListModelMixin, GenericAPIView):
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
全部优化后:
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)