视图类中配置:filter_backends = [OrderingFilter] # 1 入口---》查询所有---》ListModelMixin---》list---》完成了过滤 # 2 ListModelMixin---》list的方法--》必须配合继承GenericAPIView class ListModelMixin: def list(self, request, *args, **kwargs): # self.get_queryset() 所有数据---》all() # self.filter_queryset 完成了过滤和排序 queryset = self.filter_queryset(self.get_queryset()) serializer = self.get_serializer(queryset, many=True) return Response(data=serializer.data) # 3 self.filter_queryset(总数据qs对象) ---》视图类的对象---》找到了GenericAPIView def filter_queryset(self, queryset): # 配置的一个个过滤类 for backend in list(self.filter_backends): # 过滤类()---得到对象---》调用了对象的filter_queryset方法 # self.request:request # queryset:qs总数据 # self:视图类的对象 # queryset 过滤后的数据 queryset = backend().filter_queryset(self.request, queryset, self) return queryset #经过你配置的过滤类排序类都操作完了--》返回qs对象 # 4 内置的具体如何排序的--》OrderingFilter--》一定重写了filter_queryset方法--》完成的排序 def filter_queryset(self, request, queryset, view): # 通过视图类中配置的排序字段:view+前端传入的条件:request # ordering=price,id ordering = self.get_ordering(request, queryset, view) # [price,id] if ordering: return queryset.order_by(*ordering) return queryset # 5 内置过滤如何实现---》SearchFilter--》一定重写了filter_queryset方法--》完成了过滤 def filter_queryset(self, request, queryset, view): # 拿到查询字段:配置视图类中得 search_fields = self.get_search_fields(view, request) # 拿到前端传入的查询字段 search_terms = self.get_search_terms(request) # 都没有,就没过滤 if not search_fields or not search_terms: return queryset orm_lookups = [ self.construct_search(str(search_field)) for search_field in search_fields ] base = queryset conditions = [] for search_term in search_terms: queries = [ models.Q(**{orm_lookup: search_term}) for orm_lookup in orm_lookups ] conditions.append(reduce(operator.or_, queries)) # 根据search的字段和传入的参数,拼接成or的查询条件,进行查询,返回结果 queryset = queryset.filter(reduce(operator.and_, conditions)) return queryset
.
只要写了函数,配置在配置文件中,以后 视图类的方法或三大认证,只要除了异常都会调用咱们配置的函数 # 2 APIView中 dispatch中 有个try ,肯定在except 中执行的 APIView---dispatch---》 try: # 三大认证 self.initial(request, *args, **kwargs) # 视图类的方能股份 if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc: # 就是这里,exc 异常对象 response = self.handle_exception(exc) # 3 self.handle_exception(exc)--->视图类的对象---》APIView中找 def handle_exception(self, exc): #### 开始:如果没有认证通过,http响应状态码编程 403,向响应头放了点东西#### if isinstance(exc, (exceptions.NotAuthenticated,exceptions.AuthenticationFailed)): auth_header = self.get_authenticate_header(self.request) if auth_header: exc.auth_header = auth_header else: exc.status_code = status.HTTP_403_FORBIDDEN #### 结束#### #exception_handler:就是我们写的那个 处理函数 exception_handler = self.get_exception_handler() # 上下文 context = self.get_exception_handler_context() # exception_handler 咱们写的异常处理函数,接收两个参数 # 第一个是错误对象 # 第二个是:上下文--》对象--》里面有当次请求的requet,view response = exception_handler(exc, context) # 如果咱们写的 异常处理函数返回了None,它就不管了,直接抛给前端 if response is None: self.raise_uncaught_exception(exc) return response # 4 self.get_exception_handler() 如果拿到咱么写的异常处理函数的 APIView def get_exception_handler(self): """ 我们配置文件配置了,这个就会返回它 REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler', } 我们如果没配,就是默认的 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler' """ # 你在配置文件中配置的 return self.settings.EXCEPTION_HANDLER # 5 读 EXCEPTION_HANDLER': 'rest_framework.views.exception_handler def exception_handler(exc, context): if isinstance(exc, Http404): exc = exceptions.NotFound() elif isinstance(exc, PermissionDenied): exc = exceptions.PermissionDenied() # drf所有的异常,都继承了APIException,drf所有异常,都会走到这里 if isinstance(exc, exceptions.APIException): if isinstance(exc.detail, (list, dict)): data = exc.detail else: data = {'detail': exc.detail} # {detail:'认证失败'} # Response(data={'detail': exc.detail}) # Response(data=字典或列表) return Response(data, status=exc.status_code, headers=headers) # 除了drf的异常,都没管,直接抛给前端 return None # 6 自己写 drf已经处理了,统一返回格式,稍微做个处理
只有查询所有才分页====》list # 2 ListModelMixin 的list class ListModelMixin: def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) # 分页 调用咱们写的分页类对象的paginate_queryset方法返回了 分页后的qs对象 page = self.paginate_queryset(queryset) if page is not None: # 完成序列化 serializer = self.get_serializer(page, many=True) # 返回格式 ''' { count": 5, "next": "", "previous": "", "results": [] # 原来的应该返回的数据 } ''' return self.get_paginated_response(serializer.data) ##### 分页 结束### serializer = self.get_serializer(queryset, many=True) return Response(data=serializer.data) #3 self.paginate_queryset(queryset) self是视图类的对象,ListModelMixin中没有这个方法 # 4 GenericAPIView 的 self.paginate_queryset(queryset) # 视图类的对象中没有paginator,就不分页 def paginate_queryset(self, queryset): if self.paginator is None: return None # self.paginator 到底是啥? 我们配置在视图类上的分页类的对象 # 我们写的分页类对象的 paginate_queryset 方法 return self.paginator.paginate_queryset(queryset, self.request, view=self) # 5 self.paginator @property def paginator(self): if not hasattr(self, '_paginator'): if self.pagination_class is None: self._paginator = None else: # 一开始没有,走了这句 self._paginator = self.pagination_class() return self._paginator # 它就是我们配置的分页类的对象 # 6 self.pagination_class() 如果我们视图类中配置了:pagination_class = CommonPageNumberPagination 如果我们没配:项目自己的配置文件,drf内置的 pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
from rest_framework.viewsets import ViewSet class BookView(ViewSet): def list(self, request): book_list = Book.objects.all() # 调用咱们写的分页类对象的paginate_queryset方法返回了 分页后的qs对象 pagenation = CommonPageNumberPagination() page = pagenation.paginate_queryset(book_list, request, self) ser = BookSerializer(instance=page, many=True) # return pagenation.get_paginated_response(ser.data) return Response({'code': 100, 'msg': '查询成功', 'count': pagenation.page.paginator.count, 'next': pagenation.get_next_link(), 'pre': pagenation.get_previous_link(), 'result': ser.data})