• 【Django】REST_Framework框架——GenericAPIView类源码解析


    在这里插入图片描述

    一、GenericAPIView源码解析

    GenericAPIView继承自 APIView,也就是在 APIView基础上再做了一层封装

    类属性

    queryset = None
    serializer_class = None
    lookup_field = ‘pk’
    lookup_url_kwarg = None
    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

    1、queryset

    queryset是用来控制视图返回给前端的数据。如果没什么逻辑,可以直接写在视图的类属性中,如果逻辑比较复杂,也可以重写get_queryset方法用来返回一个queryset对象。如果重写了get_queryset,那么以后获取queryset的时候就需要通过调用get_queryset方法。因为queryset` 这个属性只会调用一次,以后所有的请求都是使用他的缓存。

    2、serializer_class

    serializer_class用来验证和序列化、反序列化数据的。也是可以通过直接设置这个属性,也可以通过重写get_serializer_class来实现。

    3、lookup_field

    在检索的时候,根据什么参数进行检索。默认是pk,也就是主键。

    4、lookup_url_kwarg

    在检索的url中的参数名称。默认没有设置,跟lookup_field保持一致。

    5、filter_backends

    用于过滤查询集的过滤器后端类的列表。默认值与DEFAULT_FILTER_BACKENDS 设置的值相同。

    6、pagination_class

    当分页列出结果时应使用的分页类。默认值与 DEFAULT_PAGINATION_CLASS 设置的值相同,即 ‘rest_framework.pagination.PageNumberPagination’。

    方法

    get_object()
    get_queryset()
    get_serializer()
    get_serializer_class()
    get_serializer_context()
    paginate_queryset()
    filter_queryset()

    1、get_queryset()

    get_queryset默认是返回数据库全部数据,如果想返回其他数据,需要自定义

    def get_queryset(self):
            """
            Get the list of items for this view.
            This must be an iterable, and may be a queryset.
            Defaults to using `self.queryset`.
    
            This method should always be used rather than accessing `self.queryset`
            directly, as `self.queryset` gets evaluated only once, and those results
            are cached for all subsequent requests.
    
            You may want to override this if you need to provide different
            querysets depending on the incoming request.
    
            (Eg. return a list of items that is specific to the user)
            """
            assert self.queryset is not None, (
                "'%s' should either include a `queryset` attribute, "
                "or override the `get_queryset()` method."
                % self.__class__.__name__
            )
    
            queryset = self.queryset
            if isinstance(queryset, QuerySet):
                # Ensure queryset is re-evaluated on each request.
                queryset = queryset.all()
            return queryset
    
    • 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

    2、get_object()

    该方法是用于在数据检索(通过pk查找)的时候,返回一条数据的。
    不需要重写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
    
    • 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

    3、get_serializer()

    返回应该用于验证和反序列化输入以及序列化输出的序列化器实例
    不需要重写get_serializer()方法,直接调用即可

    def get_serializer(self, *args, **kwargs):
            """
            Return the serializer instance that should be used for validating and
            deserializing input, and for serializing output.
            """
            serializer_class = self.get_serializer_class()
            kwargs.setdefault('context', self.get_serializer_context())
            return serializer_class(*args, **kwargs)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4、get_serializer_class()

    返回用于序列化的类。默认使用 self.serializer_class。如果您需要根据传入请求提供不同的序列化,您可能需要重写它。

    def get_serializer_class(self):
            """
            Return the class to use for the serializer.
            Defaults to using `self.serializer_class`.
    
            You may want to override this if you need to provide different
            serializations depending on the incoming request.
    
            (Eg. admins get full serialization, others get basic serialization)
            """
            assert self.serializer_class is not None, (
                "'%s' should either include a `serializer_class` attribute, "
                "or override the `get_serializer_class()` method."
                % self.__class__.__name__
            )
    
            return self.serializer_class
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    5、filter_queryset()

    默认不需要过滤,如果需要过滤需要重写filter_queryset()方法

    def filter_queryset(self, queryset):
            """
            Given a queryset, filter it with whichever filter backend is in use.
    
            You are unlikely to want to override this method, although you may need
            to call it either from a list view, or from a custom `get_object`
            method if you want to apply the configured filtering backend to the
            default queryset.
            """
            for backend in list(self.filter_backends):
                queryset = backend().filter_queryset(self.request, queryset, self)
            return queryset
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    6、paginator()

    a、paginator()方法让装饰器@property进行修饰,表示将方法暴露出去变成了属性
    b、判断类属性中是否包含pagination_class方法,如果存在pagination_class,则变为pagination_class()方法并且赋值给self._paginator,返回self._paginator

        @property
        def paginator(self):
            """
            The paginator instance associated with the view, or `None`.
            """
            if not hasattr(self, '_paginator'):
                if self.pagination_class is None:
                    self._paginator = None
                else:
                    self._paginator = self.pagination_class()
            return self._paginator
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7、paginate_queryset()

    a、默认不需要分页,如果需要分页需要重写paginate_queryset()方法
    b、如果self.paginator 为 None,不需要进行过滤,否则需要通过self.paginator.paginate_queryset()方法进行过滤

    def paginate_queryset(self, queryset):
            """
            Return a single page of results, or `None` if pagination is disabled.
            """
            if self.paginator is None:
                return None
            return self.paginator.paginate_queryset(queryset, self.request, view=self)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我的视图

    重写了get_queryset()方法和get_serializer_class()方法

    from rest_framework.generics import GenericAPIView
    from rest_framework.response import Response
    
    
    from app2.models import NewsChannel
    from app2.serializers1 import NewsChannelSerializer,NewsChannel1Serializer
    
    
    class ChannelsAPIView(GenericAPIView):
        queryset = NewsChannel.objects.all()
        serializer_class = NewsChannelSerializer
    
    
        def get_queryset(self):
            return NewsChannel.objects.filter(id__exact=2)
    
        def get_serializer_class(self):
            return NewsChannel1Serializer
    
    
        def get(self, request,*args,**kwargs):
            queryset=self.get_queryset()
            serializer=self.get_serializer(instance=queryset,many=True)
            return Response(serializer.data)
    
        def post(self,request):
            serializer=self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)
    
    • 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

    执行结果:

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    虚拟运行环境管理工具Vagrant详细使用教程
    spring boot社区居民健康档案管理系统毕业设计源码220940
    【数据结构】&&【C++】红黑树RBTree的模拟实现(平衡搜索二叉树)
    断点测试怎么做?一文教你用Charles 工具做好接口测试!
    Lambda表达式
    【MATLAB源码-第71期】基于matlab的萤火虫算法(FA)的无人机三维地图路径规划,输出最短路径和适应度曲线。
    数学建模学习(76):多目标线性规划模型(理想法、线性加权法、最大最小法),模型敏感性分析
    【计算机视觉】图像形成与颜色
    计算机二级公共基础知识-2023
    如何避免重复创建线程?创建线程池的方式有哪些?各自优缺点有哪些?
  • 原文地址:https://blog.csdn.net/YZL40514131/article/details/126575424