在Django学习[60]中的views.py的类视图中,使用继承了viewsets.ModelViewSet

Viewsets

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

    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):
        """
        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)
                setattr(self, method, handler)

            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)

第15行重写了as_view,添加了一些过滤和反向解析

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

继承自generics.GenericAPIViewViewSetMixin

generics.GenericAPIView在上一篇已经介绍过。

ViewSet

class ViewSet(ViewSetMixin, views.APIView):
    """
    The base ViewSet class does not provide any actions by default.
    """
    pass

默认什么都不支持,需要自己手动实现

ReadOnlyModelViewSet

只读的模型的视图集合

class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    """
    A viewset that provides default `list()` and `retrieve()` actions.
    """
    pass
  • 继承自:

    • mixins.RetrieveModelMixin
    • mixins.ListModelMixin
    • GenericViewSet
  • 只能获取数据,所以只读

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
  • 继承自:

    • mixins.CreateModelMixin
    • mixins.RetrieveModelMixin
    • mixins.UpdateModelMixin
    • mixins.DestroyModelMixin
    • mixins.ListModelMixin
    • GenericViewSet

总结这些viewset作用就是,将CRUD这些进行组合,并且重写了as_view以便于和路由对接。

Viewset实践

上一篇直接继承了ListCreateAPIView,现在使用封装后的Viewsets作为继承的视图类。

Views.py

新建一个class类

class GameModelViewSet(ModelViewSet):

    serializer_class = GameSerializer

    queryset = Game.objects.all()

urls.py

注册路由时,也可以使用as_view,但是比较麻烦,所以使用router来代替

router = DefaultRouter()

router.register(r'games', GameModelViewSet)

总URLS

from django.contrib import admin
from django.urls import path, include

from App.urls import router

urlpatterns = [
    path('admin/', admin.site.urls),
    # path('app/', include('App.urls')),
    path('app/', include(router.urls)),
]

postman测试

get访问所有数据

post新建

get访问单个数据

delete步骤自行测试

restframework分页器

开发文档:https://q1mi.github.io/Django-REST-framework-documentation/api-guide/pagination_zh/

当开发完接口之后,需要实现接口数据的分片,比如每次只返回5条数据给客户端,而不是每次都返回全部数量这样能有效减少服务器压力,减少客户端的加载时间,提高响应速度,客户端需要携带参数访问接口。

分页器类型介绍

分页器分为三种:

  • PageNumberPagination

    • 常规单页分页器
    • 通过page参数访问某一个单个分片数据
  • LimitOffsetPagination

    • 偏移分页
    • 这种分页样式反映了查找多个数据库记录时使用的语法。客户端包括“limit”和“offset”查询参数。limit指示要返回的项目的最大数目,这相当于其他样式中的 page_size。offset指示查询相对于完整的未分页项的起始位置。
  • CursorPagination

    • 游标分页
    • 基于cursor的分页提供了一个不透明的“游标”指示器,客户端可以使用它对结果集进行分页。这种分页样式只显示正向和反向控件,而不允许客户端导航到任意位置。

基于cursor的分页要求结果集中的项具有唯一的、不变的顺序。此顺序通常可能是记录上的创建时间戳,因为它提为分页供了一致的顺序。
基于cursor的分页比其他方案更复杂。它还要求结果集呈现固定的顺序,并且不允许客户端任意索引结果集。但是,它确实提供了以下好处:

  - 提供一致的分页视图。当恰当地使用时,`CursorPagination` 可以确保客户端在翻阅记录时永远不会看到同一个项目两次,即使在分页过程中其他客户端正在插入新的项目时亦是如此。
  - 支持使用非常大的数据集。对于极其庞大的数据集,使用基于offset的分页样式进行分页可能会变得效率低下或无法使用。基于cursor的分页方案具有固定时间的属性,并且不会随着数据集大小的增加而减慢。

实践

首先在views中注册分页器:

class LargeResultsSetPagination(PageNumberPagination):
    page_size = 2
    page_size_query_param = 'page_size'
    max_page_size = 8

在Viewset类视图中使用分页器:

class GameModelViewSet(ModelViewSet):
    serializer_class = GameSerializer

    queryset = Game.objects.all()

    pagination_class = LargeResultsSetPagination

接着进行携带page参数get请求接口:


可以看到只返回了两条数据,并且客户端通过循环page参数,可继续读取下面的数据。

总结

router

使用了ViewSet,封装了路由的设置,可以直接使用router来自动设置路由路径

功能

想要实现对应的功能,只需要继承对应minxins中的类即可:

  • mixins.CreateModelMixin
  • mixins.RetrieveModelMixin
  • mixins.UpdateModelMixin
  • mixins.DestroyModelMixin
  • mixins.ListModelMixin
  • GenericViewSet

    APIView

  • 子类

    • generics包中
    • GenericAPIView

      • 增加的模型的获取操作
      • get_queryset
      • get_object

        • lookup_field 默认pk
      • get_serializer
      • get_serializer_class
      • get_serializer_context
      • filter_queryset
      • paginator
      • paginate_queryset
      • get_paginated_response
    • CreateAPIView

      • 创建的类视图
      • 继承自GenericAPIView
      • 继承自CreateModelMixin
      • 实现了post进行创建
    • ListAPIView

      • 列表的类视图
      • 继承自GenericAPIView
      • 继承自ListModelMixin
      • 实现了get
    • RetrieveAPIView

      • 查询单个数据的类视图
      • 继承自GenericAPIView
      • 继承自RetrieveModelMixin
      • 实现了get
    • DestroyAPIView

      • 销毁数据的类视图,删除数据的类视图
      • 继承自GenericAPIView
      • 继承自DestroyModelMixin
      • 实现了delete
    • UpdateAPIView

      • 更新数据的类视图
      • 继承自GenericAPIView
      • 继承自UpdateModelMixin
      • 实现了 put,patch
    • ListCreateAPIView

      • 获取列表数据,创建数据的类视图
      • 继承自GenericAPIView
      • 继承自ListModelMixin
      • 继承自CreateModelMixin
      • 实现了 get,post
    • RetrieveUpdateAPIView

      • 获取单个数据,更新单个数据的类视图
      • 继承自GenericAPIView
      • 继承自RetrieveModelMixin
      • 继承自UpdateModelMixin
      • 实现了 get, put, patch
    • RetrieveDestroyAPIView

      • 获取单个数据,删除单个数据
      • 继承自GenericAPIView
      • 继承自RetrieveModelMixin
      • 继承自DestroyModelMixin
      • 实现了 get, delete
    • RetrieveUpdateDestroyAPIView

      • 获取单个数据,更新单个数据,删除单个数据的类视图
      • 继承自GenericAPIView
      • 继承自RetrieveModelMixin
      • 继承自UpdateModelMixin
      • 继承自DestroyModelMixin
      • 实现了 get, put, patch, delete
  • mixins

    • CreateModelMixin

      • create
      • perform_create
      • get_success_headers
    • ListModelMixin

      • list

        • 查询结果集,添加分页,帮你序列化
    • RetrieveModelMixin

      • retrieve

        • 获取单个对象并进行序列化
    • DestroyModelMixin

      • destroy

        • 获取单个对象
        • 调用执行删除
        • 返回Respon 状态码204
      • perform_destroy

        • 默认是模型的delete
        • 如果说数据的逻辑删除

          • 重写进行保存
    • UpdateModelMixin

      • update

        • 获取对象,合法验证
        • 执行更新
      • perform_update
      • partial_update

        • 差量更新,对应的就是patch
  • viewsets

    • ViewSetMixin

      • 重写as_view
    • GenericViewSet

      • 继承自GenericAPIView
      • 继承自ViewSetMixin
    • ViewSet

      • 继承自APIView
      • 继承自ViewSetMixin
      • 默认啥都不支持,需要自己手动实现
    • ReadOnlyModelViewSet

      • 只读的模型的视图集合
      • 继承自RetrieveModelMixin
      • 继承自ListModelMixin
      • 继承自GenericViewSet
    • ModelViewSet

      • 直接封装对象的所有操作
      • 继承自GenericViewSet
      • 继承自CreateModelMixin
      • 继承自RetrieveModelMixin
      • 继承自UpdateModelMixin
      • 继承自DestroyModelMixin
      • 继承自ListModelMixin
最后修改:2024 年 03 月 13 日
如果觉得我的文章对你有用,请随意赞赏