Python 学习笔记(十八)--Django REST Framework之GenericAPIView

Django REST framwork 提供的视图主要作用:

  • 控制序列化器的执行(检验、保存、转换数据)
  • 控制数据库模型的操作

Django REST framwork 提供了众多的通用视图基类与扩展类,以简化视图的编写。

1.基类

views.APIView  与 GenericsAPIView,后者继承前者。

class GenericAPIView(views.APIView):
    """
    Base class for all other generic views.
    """

2.GenericAPIView的属性和方法

通用视图类主要作用就是把视图中的独特的代码抽取出来,让视图方法中的代码更加通用,方便把通用代码进行简写。

3. GenericAPIView 的属性queryset

复制代码
class GenericAPIView(views.APIView):
    """
    Base class for all other generic views.
    """
    # You'll need to either set these attributes,
    # or override `get_queryset()`/`get_serializer_class()`.
    # If you are overriding a view method, it is important that you call
    # `get_queryset()` instead of accessing the `queryset` property directly,
    # as `queryset` will get evaluated only once, and those results are cached
    # for all subsequent requests.
    queryset = None
    serializer_class = None
复制代码

在开发者编写的视图类中,可以直接为queryset 赋值。

例如:

queryset = XXX.objects.all() ---XXX代表某个model
serializer_class = XXXXX, --表示使用那个序列化类 来序列化 指定的数据。

4. GenericAPIView 的方法get_queryset

返回视图使用的查询集,主要用来提供给Minxin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回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
复制代码

5.GenericAPIView 的方法get_serializer

对象集即多行数据时,需要传入参数many=True

返回序列化器对象,主要用来提供给Mixin扩展类使用,如果在视图中想要获取序列化器对象,也可以直接调用此方法。

    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)

子方法get_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
复制代码

6.GenericAPIView 的方法get_object

返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在视图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404.
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。

复制代码
    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()) ###从这个代码可以看出,是对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
复制代码

 7.5个视图扩展类

from rest_framework.mixins importListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin

作用

"""
Basic building blocks for generic class based views.

We don't bind behaviour to http method handlers yet,
which allows mixin classes to be composed in interesting ways.
"""

 8.GenericAPIView的视图子类

rest_framework的mixins 的子类 和 GenericAPIView 结合,创造了9个GenericAPIView的视图子类。

 9.视图子类ListAPIView

class ListAPIView(mixins.ListModelMixin,
                  GenericAPIView):
    """
    Concrete view for listing a queryset.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

 10. 继承多个子类,方法大集合

from rest_framework.viewsets import ModelViewSet

源码

复制代码
class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass
复制代码

 需要留意的是 ModelViewSet 继承的是GenericViewSet

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default,
    but does include the base set of generic view behavior, such as
    the `get_object` and `get_queryset` methods.
    """
    pass

还继承了ViewSetMixin

 11. ViewSetMixin

复制代码
class ViewSetMixin:
    """
    This is the magic.

    Overrides `.as_view()` so that it takes an `actions` keyword that performs
    the binding of HTTP methods to actions on the Resource.

    For example, to create a concrete view binding the 'GET' and 'POST' methods
    to the 'list' and 'create' actions...

    view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
    """
复制代码

 需要特比注意的是,类重写了as_view方法,【当调用时,actions参数必须赋值,否则报错。例如as_view({'get':'list','post':'create'}) 】

actions 对应的参数为字典类型。

即路由中(url)需要配置对应关系,例如{'get':'list'},表示当get请求到来,就会执行list方法。

复制代码
    @classonlymethod
    def as_view(cls, actions=None, **initkwargs): ##传入的参数与APIView的都不一样
        """
        Because of the way class based views create a closure around the
        instantiated view, we need to totally reimplement `.as_view`,
        and slightly modify the view function that is created and returned.
        """
        # The name and description initkwargs may be explicitly overridden for
        # certain route configurations. eg, names of extra actions.
        cls.name = None
        cls.description = None

        # The suffix initkwarg is reserved for displaying the viewset type.
        # This initkwarg should have no effect if the name is provided.
        # eg. 'List' or 'Instance'.
        cls.suffix = None

        # The detail initkwarg is reserved for introspecting the viewset type.
        cls.detail = None

        # Setting a basename allows a view to reverse its action urls. This
        # value is provided by the router through the initkwargs.
        cls.basename = None

        # actions must not be empty
        if not actions:
            raise TypeError("The `actions` argument must be provided when "
                            "calling `.as_view()` on a ViewSet. For example "
                            "`.as_view({'get': 'list'})`")

        # sanitize keyword arguments
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r" % (
                    cls.__name__, key))

        # name and suffix are mutually exclusive
        if 'name' in initkwargs and 'suffix' in initkwargs:
            raise TypeError("%s() received both `name` and `suffix`, which are "
                            "mutually exclusive arguments." % (cls.__name__))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)

            if 'get' in actions and 'head' not in actions:
                actions['head'] = actions['get']

            # We also store the mapping of request methods to actions,
            # so that we can later set the action attribute.
            # eg. `self.action = 'list'` on an incoming GET request.
            self.action_map = actions

            # Bind methods to actions
            # This is the bit that's different to a standard view
            for method, action in actions.items():
                handler = getattr(self, action)   ##handler 就变成了action变量对应的内存地址了
                setattr(self, method, handler)    ##通过反射,handler 赋值给self.method
            ##经过上面的for循环,对象有了对象.get(对应的list)\对象.post(对应的create) ....这类方法。
self.request
= request self.args = args self.kwargs = kwargs # And continue as usual return self.dispatch(request, *args, **kwargs) # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) # We need to set these on the view function, so that breadcrumb # generation can pick out these bits of information from a # resolved URL. view.cls = cls view.initkwargs = initkwargs view.actions = actions return csrf_exempt(view)
复制代码

 12 drf 默认配置文件查找顺序

(1)先从本视图类中查找;

(2)项目的setting配置文件中查找;

(3)drf默认的文件中查找(.../lib/site-packages/django/conf/global_settings.py)

 
posted @   东山絮柳仔  阅读(201)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示