drf 入门-精通 10days

发布时间 2023-12-29 15:27:38作者: 拆尼斯、帕丁顿

过滤排序源码

 视图类中配置: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已经处理了,统一返回格式,稍微做个处理

基于APIView实现分页

读源码

 只有查询所有才分页====》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

继承APIView写分页

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})