zoukankan      html  css  js  c++  java
  • DRF Views Inheritance Relationships

    OverView

     

    Django View -- Root

    https://docs.djangoproject.com/en/3.2/ref/class-based-views/base/#view

    所有view视图的基类, 此类不是通用视图,被业务视图继承。

    class django.views.generic.base.View

    The master class-based base view. All other class-based views inherit from this base class. It isn’t strictly a generic view and thus can also be imported from django.views.

    主要功能是做映射:  http method --> view method

    HTTP METHOD -->  VIEW.METHOD

    GET     -->  View.get

    POST     -->  View.post

    PUT     -->  View.put

    DELETE   -->  View.delete

    视图业务定义在 http method名称的方法中。

    from django.http import HttpResponse
    from django.views import View
    
    class MyView(View):
    
        def get(self, request, *args, **kwargs):
            return HttpResponse('Hello, World!')

    使用as_view方法,将视图类转换为 callable 视图。

    from django.urls import path
    
    from myapp.views import MyView
    
    urlpatterns = [
        path('mine/', MyView.as_view(), name='my-view'),
    ]

    DRF APIView --> Django View

     https://www.django-rest-framework.org/api-guide/views/

    继承了Dangjo View,

      同Django View相同点:

        有 HTTP METHOD 到 VIEW METHOD的映射

        业务方法定义在 VIEW METHOD 方法中

      不同的地方:

        新增了一些控制属性

    Using the APIView class is pretty much the same as using a regular View class, as usual, the incoming request is dispatched to an appropriate handler method such as .get() or .post(). Additionally, a number of attributes may be set on the class that control various aspects of the API policy.

    DRF 控制属性

    https://testdriven.io/blog/drf-views-part-1/

    AttributeUsageExamples
    renderer_classes determines which media types the response returns JSONRenderer, BrowsableAPIRenderer
    parser_classes determines which data parsers for different media types are allowed JSONParser, FileUploadParser
    authentication_classes determines which authentication schemas are allowed for identifying the user TokenAuthentication, SessionAuthentication
    throttle_classes determines if a request should be authorized based on the rate of requests AnonRateThrottle, UserRateThrottle
    permission_classes determines if a request should be authorized based on user credentials IsAuthenticated, DjangoModelPermissions
    content_negotiation_class selects one of the multiple possible representations of the resource to return to a client (unlikely you'll want to set it up) only custom content negotiation classe

    在view.method 之外增加 控制属性

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import authentication, permissions
    from django.contrib.auth.models import User
    
    class ListUsers(APIView):
        """
        View to list all users in the system.
    
        * Requires token authentication.
        * Only admin users are able to access this view.
        """
        authentication_classes = [authentication.TokenAuthentication]
        permission_classes = [permissions.IsAdminUser]
    
        def get(self, request, format=None):
            """
            Return a list of all users.
            """
            usernames = [user.username for user in User.objects.all()]
            return Response(usernames)

    DRF GenericAPIView --> DRF APIView

    https://www.django-rest-framework.org/api-guide/generic-views/#genericapiview

    DRF APIView 相比 Django View, 增加了一些控制属性, 例如对接口的访问权限和限流进行控制。

    DRF GenericAPIView 相比 DRF APIView,又增加了一些控制属性, 这些控制属性,是专门面向典型的多实例数据(数据库表)设计,

    让用户简单定义一个API, 可以完成对应一个数据库表的CRUD操作。

    This class extends REST framework's APIView class, adding commonly required behavior for standard list and detail views.

    如下三个:

    queryset --> 使用Model定义查询集合

    serializer_class --> 定义模型的序列化类

    pagination_class --> 分页控制

    • queryset - The queryset that should be used for returning objects from this view. Typically, you must either set this attribute, or override the get_queryset() method. If you are overriding a view method, it is important that you call get_queryset() instead of accessing this property directly, as queryset will get evaluated once, and those results will be cached for all subsequent requests.
    • serializer_class - The serializer class that should be used for validating and deserializing input, and for serializing output. Typically, you must either set this attribute, or override the get_serializer_class() method.
    • pagination_class - The pagination class that should be used when paginating list results. Defaults to the same value as the DEFAULT_PAGINATION_CLASS setting, which is 'rest_framework.pagination.PageNumberPagination'. Setting pagination_class=None will disable pagination on this view.

    https://testdriven.io/blog/drf-views-part-2/#genericapiview

    基于新增的控制属性, 可以非常方便地实现 GET 和 DELETE 业务。

    from rest_framework.generics import GenericAPIView
    from rest_framework.response import Response
    
    class RetrieveDeleteItem(GenericAPIView):
    
        serializer_class = ItemSerializer
        queryset = Item.objects.all()
    
        def get(self, request, *args, **kwargs):
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)
    
        def delete(self, request, *args, **kwargs):
            instance = self.get_object()
            instance.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)

     

    DRF Concrete View Classes --> DRF GenericAPIView

    DRF GenericAPIView 是从数据层面上定义了一些公共属性, 这些属性服务于单个数据库表,

    使得在 get delete方法中,可以方便地操作数据, 和 序列化数据, 见上节GenericAPIView示例代码。

    如果后台逻辑非常简单,仅仅局限在数据库表的 CRUD操作, 那么get delete方法中的代码就存在公用性,

    更好的方法是将这些公共的代码,封装起来(Mixins),使用的时候继承使用。

    Mixins

    在各个Mixin中封装好 view.method中的公用代码。

    https://www.django-rest-framework.org/api-guide/generic-views/#mixins

    The mixin classes provide the actions that are used to provide the basic view behavior. Note that the mixin classes provide action methods rather than defining the handler methods, such as .get() and .post(), directly. This allows for more flexible composition of behavior.

    The mixin classes can be imported from rest_framework.mixins.

    所有的Mixin都是不能单独使用的, 需要个GenericAPIView搭配使用。

    但是这些Mixin仅仅做公共代码逻辑的封装,并不提供view.method的实现。

    https://testdriven.io/blog/drf-views-part-2/#mixins

    Mixins provide bits of common behavior. They cannot be used standalone; they must be paired with GenericAPIView to make a functional view. While the mixin classes provide create/retrieve/update/delete actions, you still need to bind the appropriate actions to the methods.

    MixinUsage
    CreateModelMixin Create a model instance
    ListModelMixin List a queryset
    RetrieveModelMixin Retrieve a model instance
    UpdateModelMixin Update a model instance
    DestroyModelMixin Delete a model instance

    例如 RetrieveModelMixin 仅仅实现 retrieve 方法。

    class RetrieveModelMixin:
        """
        Retrieve a model instance.
        """
        def retrieve(self, request, *args, **kwargs):
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)

    基于此, 可以使得 view.method更加简洁, 例如。

    实际上,如无特殊逻辑(数据库表操作之外的逻辑), 考虑到通用性, get 和 post的方法, 也不应该让用户维护。

    from rest_framework import mixins
    from rest_framework.generics import GenericAPIView
    
    class CreateListItems(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):
    
        serializer_class = ItemSerializer
        queryset = Item.objects.all()
    
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)

    Concrete View Classes

    具体的视图类,就是为了考虑的数据库表操作的通用性, 竭尽所能,让用户少维护代码。

    https://www.django-rest-framework.org/api-guide/generic-views/#concrete-view-classes

    The following classes are the concrete generic views. If you're using generic views this is normally the level you'll be working at unless you need heavily customized behavior.

    The view classes can be imported from rest_framework.generics.

    例如ListCreateAPIView, 实现了 Mixin.method 绑定到 View.method中。

    https://testdriven.io/blog/drf-views-part-2/#concrete-views

    # https://github.com/encode/django-rest-framework/blob/3.12.4/rest_framework/generics.py#L232
    
    class ListCreateAPIView(mixins.ListModelMixin,
                            mixins.CreateModelMixin,
                            GenericAPIView):
    
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)

    具体使用上,就变成了声明式, 无需关心 get 和 post方法实现:

    from rest_framework.generics import ListCreateAPIView
    
    class ListCreateItems(ListCreateAPIView):
    
        authentication_classes = [TokenAuthentication]
    
        queryset = Item.objects.all()
        serializer_class = ItemSerializer

    具体视图类包括以下若干种:

    https://testdriven.io/blog/drf-views-part-2/#concrete-views

    ClassUsageMethod handlerExtends mixin
    CreateAPIView create-only post CreateModelMixin
    ListAPIView read-only for multiple instances get ListModelMixin
    RetrieveAPIView read-only for single instance get RetrieveModelMixin
    DestroyAPIView delete-only for single instance delete DestroyModelMixin
    UpdateAPIView update-only for single instance put, patch UpdateModelMixin
    ListCreateAPIView read-write for multiple instances get, post CreateModelMixin, ListModelMixin
    RetrieveUpdateAPIView read-update for single instance get, put, patch RetrieveModelMixin, UpdateModelMixin
    RetrieveDestroyAPIView read-delete for single instance get, delete RetrieveModelMixin, DestroyModelMixin
    RetrieveUpdateDestroyAPIView read-update-delete for single instance get, put, patch, delete RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin

    ViewSet --> APIView, ViewSetMixin

    ViewSet 继承于 APIView,

      拥有两个能力:

        (1)HTTP.METHOD 到 VIEW.METHOD 映射能力 (django view)

        (2)定义接口访问控制属性 (DRF APIView)

      其还继承了 ViewSetMixin

        此类重写了 as_view 接口, 将HTTP.METHOD映射到MIXIN.ACTION. 这样 业务开发者只需要关注ACTION 接口实现。

    ViewSetMixin

    https://testdriven.io/blog/drf-views-part-3/#viewset-class

    ViewSetMixin is a class where all the "magic happens". It's the only class that all four of the ViewSets share. It overrides the as_view method and combines the method with the proper action.

    MethodList / DetailAction
    post List create
    get List list
    get Detail retrieve
    put Detail update
    patch Detail partial_update
    delete Detail destroy

    ViewSet

    继承ViewSet的子类(业务类)需要实现 VIEW.ACTION.

    https://www.django-rest-framework.org/api-guide/viewsets/#viewset

    The ViewSet class inherits from APIView. You can use any of the standard attributes such as permission_classes, authentication_classes in order to control the API policy on the viewset.

    The ViewSet class does not provide any implementations of actions. In order to use a ViewSet class you'll override the class and define the action implementations explicitly.

    例如, 业务action被实现,

    但是此类是继承于APIView,将 HTTP.METHOD映射到 VIEW.METHOD

    并没有将HTTP.METHOD映射到 MIXIN.ACTION

    from django.shortcuts import get_object_or_404
    from rest_framework.response import Response
    from rest_framework.viewsets import ViewSet
    
    class ItemViewSet(ViewSet):
        queryset = Item.objects.all()
    
        def list(self, request):
            serializer = ItemSerializer(self.queryset, many=True)
            return Response(serializer.data)
    
        def retrieve(self, request, pk=None):
            item = get_object_or_404(self.queryset, pk=pk)
            serializer = ItemSerializer(item)
            return Response(serializer.data)

    Handling URLs

    ViewSet注册URL方式,使用 两种类型的 router。

    https://testdriven.io/blog/drf-views-part-3/#handling-urls

    Instead of using Django's urlpatterns, ViewSets come with a router class that automatically generates the URL configurations.

    DRF comes with two routers out-of-the-box:

    1. SimpleRouter
    2. DefaultRouter

    The main difference between them is that DefaultRouter includes a default API root view:

    DRF Browsable API

    The default API root view lists hyperlinked list views, which makes navigating through your application easier.

    例如:

    # urls.py
    
    from django.urls import path, include
    from rest_framework import routers
    
    from .views import ChangeUserInfo, ItemsViewSet
    
    router = routers.DefaultRouter()
    router.register(r'custom-viewset', ItemsViewSet)
    
    urlpatterns = [
        path('change-user-info', ChangeUserInfo.as_view()),
        path('', include(router.urls)),
    ]

    GenericViewSet --> GenericAPIView, ViewSetMixin

    GenericAPIView 继承于 APIView,

      同时设计了 面向数据表的 控制属性,

    GenericViewSet 继承了 GenericAPIView

      同时也继承了ViewSetMixin,将HTTP.METHOD映射到MIXIN.ACTION,子类(业务类)则需要实现ACTION。

    https://www.django-rest-framework.org/api-guide/viewsets/#genericviewset

    The GenericViewSet class inherits from GenericAPIView, and provides the default set of get_object, get_queryset methods and other generic view base behavior, but does not include any actions by default.

    In order to use a GenericViewSet class you'll override the class and either mixin the required mixin classes, or define the action implementations explicitly.

    显示实现ACTION

    例如 list create ...

    https://testdriven.io/blog/drf-views-part-3/#genericviewset

    from rest_framework import status
    from rest_framework.permissions import DjangoObjectPermissions
    from rest_framework.response import Response
    from rest_framework.viewsets import GenericViewSet
    
    class ItemViewSet(GenericViewSet):
        serializer_class = ItemSerializer
        queryset = Item.objects.all()
        permission_classes = [DjangoObjectPermissions]
    
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save(serializer)
    
            return Response(serializer.data, status=status.HTTP_201_CREATED)
    
        def list(self, request):
            serializer = self.get_serializer(self.get_queryset(), many=True)
            return self.get_paginated_response(self.paginate_queryset(serializer.data))
    
        def retrieve(self, request, pk):
            item = self.get_object()
            serializer = self.get_serializer(item)
            return Response(serializer.data)
    
        def destroy(self, request):
            item = self.get_object()
            item.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)

    直接继承MIXINS

    将mixins中实现过的 MIXINS 继承过来。

    https://testdriven.io/blog/drf-views-part-3/#genericviewset

    from rest_framework import mixins, viewsets
    
    class ItemViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    
        serializer_class = ItemSerializer
        queryset = Item.objects.all()

    ModelViewSet --> GenericViewSet, Mixins

    GenericViewSet 的缺点是, 需要自行实现 action,

    对于通用性(只需要实现数据库表操作)的场景, action都是一样的,

    此类将所有的 Mixins类继承过来, 则所有的CRUD操作都已经支持。

    https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset

    The ModelViewSet class inherits from GenericAPIView and includes implementations for various actions, by mixing in the behavior of the various mixin classes.

    The actions provided by the ModelViewSet class are .list(), .retrieve(), .create(), .update(), .partial_update(), and .destroy().

    对于一个数据库表, 只需要做如下声明, 即支持了所有的CRUD

    class ItemModelViewSet(ModelViewSet):
        serializer_class = ItemSerializer
        queryset = Item.objects.all()

    路由注册到URL

    # urls.py
    
    from django.urls import path, include
    from rest_framework import routers
    
    from .views import ChangeUserInfo, ItemsViewSet, ItemModelViewSet
    
    router = routers.DefaultRouter()
    router.register(r'custom-viewset', ItemsViewSet)
    router.register(r'model-viewset', ItemModelViewSet) # newly registered ViewSet
    
    urlpatterns = [
        path('change-user-info', ChangeUserInfo.as_view()),
        path('', include(router.urls)),
    ]

    ReadOnlyModelViewSet --> GenericViewSet, Mixins(list retrieve)

    只提供读取的 ACTION.

    https://www.django-rest-framework.org/api-guide/viewsets/#readonlymodelviewset

    The ReadOnlyModelViewSet class also inherits from GenericAPIView. As with ModelViewSet it also includes implementations for various actions, but unlike ModelViewSet only provides the 'read-only' actions, .list() and .retrieve().

    非写接口。

    from rest_framework.viewsets import ReadOnlyModelViewSet
    
    class ItemReadOnlyViewSet(ReadOnlyModelViewSet):
    
        serializer_class = ItemSerializer
        queryset = Item.objects.all()

    https://img2020.cnblogs.com/blog/603834/202110/603834-20211012235850083-113696365.png

     

    出处:http://www.cnblogs.com/lightsong/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
  • 相关阅读:
    OutputCache 缓存key的创建 CreateOutputCachedItemKey
    Asp.net Web Api源码调试
    asp.net mvc源码分析DefaultModelBinder 自定义的普通数据类型的绑定和验证
    Asp.net web Api源码分析HttpParameterBinding
    Asp.net web Api源码分析HttpRequestMessage的创建
    asp.net mvc源码分析ActionResult篇 RazorView.RenderView
    Asp.Net MVC 项目预编译 View
    Asp.net Web.config文件读取路径你真的清楚吗?
    asp.net 动态创建TextBox控件 如何加载状态信息
    asp.net mvc源码分析BeginForm方法 和ClientValidationEnabled 属性
  • 原文地址:https://www.cnblogs.com/lightsong/p/15418867.html
Copyright © 2011-2022 走看看