欢迎关注我的公众号「测试游记」
如果前端请求头中没有指定Accept 默认返回json格式的数据
$ http -v :8000/project/1/ Accept:text/html
$ http -v :8000/project/1/ Accept:application/json
!返回json
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 OKAllow: GET, POST, HEAD, OPTIONSContent-Length: 130Content-Type: application/jsonDate: Tue, 22 Oct 2019 14:19:31 GMTServer: WSGIServer/0.2 CPython/3.7.1Vary: Accept, Origin, CookieX-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 OKAllow: GET, POST, HEAD, OPTIONSContent-Length: 520Content-Type: application/jsonDate: Tue, 22 Oct 2019 14:41:54 GMTServer: WSGIServer/0.2 CPython/3.7.1Vary: Accept, Origin, CookieX-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 PageNumberPaginationclass 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 mixinsclass ProjectsList(mixins.ListModelMixin, GenericAPIView): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)
全部优化后:
from projects.models import Projectsfrom projects.serializer import ProjectModelSerializerfrom rest_framework.generics import GenericAPIViewfrom django_filters.rest_framework import DjangoFilterBackendfrom rest_framework import mixinsclass 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)