• 四,ViewSets和Routers


    概述

    在DRF中,允许在一个类中组合一组相关视图的逻辑,称为ViewSets。比如通过通用视图,可以定义列表视图、详情视图等等,但每个视图位于不同的类中,而通过ViewSets则可以将多个视图放在同一个类中。

    ViewSets也是一种基于类的视图,只不过和APIView不同的是,它并不提供如get()、post()等和HTTP请求相对应的方法,而提供的是如list()、create()这样的操作方法。

    在配置ViewSets的URL时,一般不会显示进行配置,而是使用Routers类来注册ViewSets,Routers会自动确定URL格式。

    Router可以将请求和视图自动进行匹配,并映射相应的处理逻辑。

    如果我们使用的是ViewSets而非View,那么我们就没必要自己去配置每个View对应的Url了,直接使用Router注册一个视图集,让Router来完成剩下的工作。

    1.viewsets类

    使用viewsets时需要导入所在模块:

    from rest_framework import viewsets
    

    所有的viewsets类都直接或间接的继承于ViewSetMixin这个基类。目前viewsets相关类有包中有四个类,接下来我们逐一进行总结.

    1.1.ViewSet

    ViewSets继承了ViewSetMixin和APIView,因此具有APIView的一些属性,如permission_class和authentication_classes属性,但没有实现具体的动作,所以在平时开发时,会很少用到它。该类源码如下:

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

    1.2.GenericViewSet

    GenericViewSet继承于ViewSetMixin和GenericAPIView,因此具有GenericAPIView拥有的一些属性和方法,如serializer_class、queryset、get_queryset()、get_object()等其他方法和属性,但同样也没有提供操作请求的动作实现,因此该类经常和其他generic包下的具体通用视图一起使用,如:

    class Show(viewsets.GenericViewSet,
               generics.ListCreateAPIView):
        # ListCreateAPIView将list()和create()方法和get(),post()进行了绑定
    
        serializer_class = SnippetSerializer
        queryset = Snippet.objects.all()

    该类源码如下:

    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

    1.3.ModelViewSet

    该类继承于GenericViewSet,并通过混合各种Mixin类的行为,实现了各种动作的实现。该类源码如下:

    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就可以完成包含列表视图、详情视图等多个视图和请求的操作。

    1.4.ReadOnlyModelViewSet

    该类继承于GenericViewSet,同时混合了RetrieveModelMixin和ListModelMixin,因此可以用于展示列表视图和详情视图,所以是”只读”的.该类源码如下:

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

    对整个viewsets包中的类进行总结之后,下面开始总结下如果通过Router给ViewSets配置URL。

    2.Router

    在学习ViewSets和Router之前,我们对一个View配置Url是通过如下方式进行的:

    urlpatterns = [
        path('show/', views.ShowList.as_view()),  # 用于列表视图
        path('show/<pk>', views.ShowDetail.as_view())  #用于详情视图
    ]

    可以看到,这种方式确实挺麻烦的,针对于不同的View,都需要单独进行配置。

    如果是通过ViewSets实现的View,那么通过Router就可以自动配置url了,我们只需给Router注册一个ViewSets,其他的什么都不用管。

    使用Router时需要导入所在包:

    from rest_framework import routers

    如:

    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    # 给router注册ShowViewSet
    router.register('show', views.ShowViewSet, base_name='show')
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include(router.urls)),
    ]

    其中,register()方法用来注册一个ViewSets,其所需参数如下:

    • 1.prefix:用于这组路由的URL前缀,该参数必须指定;
    • 2.viewset:ViewSets类,该参数必须指定;
    • 3.base_name:该参数可选,用于指定创建URL的名称,如果未指定,则默认使用viewsets中的queryset属性自动生成,因此,如果viewsets中没有声明queryset属性,则该参数必须设置。

    当注册之后,DRF根据具体的viewsets为我们自动生成对个URL,如存在以下viewsets和Router:

    # views.py中:
    
    from rest_framework import viewsets
    
    
    class ShowViewSet(viewsets.ModelViewSet):
    
        serializer_class = SnippetSerializer
        queryset = Snippet.objects.all()
    
    
    # urls.py中:
    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    router.register('show', views.Show, base_name='show')
    
    urlpatterns = router.urls

    生成的URL格式如下:

       ^show/$ [name='show-list']
       ^show/(?P<pk>[^/.]+)/$ [name='show-detail']

    目前在routers包中有两个类:SimpleRouter和DefaultRouter,DefaultRouter继承于SimpleRouter,这两个类没有太大区别,只不过DefaultRouter中包含一个其根API视图,它返回包含所有列表视图的超链接。这么说可能不太理解,还是用上面的例子直接对比下两个Router吧:

    首先是DefaultRouter来注册一个ViewSets,通过浏览器访问项目根Url:


    然后用SimpleRouter试试:


    这样一比较,效果一目了然,无需多费口舌。

    下面这个表格中记录了URL相关的信息,来自DRF官网:

    URL StyleHTTP MethodActionURL Name
    {prefix}/ GET list {basename}-list
    POST create
    {prefix}/{url_path}/ GET, or as specified by `methods` argument `@action(detail=False)` decorated method {basename}-{url_name}
    {prefix}/{lookup}/ GET retrieve {basename}-detail
    PUT update
    PATCH partial_update
    DELETE destroy
    {prefix}/{lookup}/{url_path}/ GET, or as specified by `methods` argument `@action(detail=True)` decorated method {basename}-{url_name}


    3.总结

    虽然使用ViewSets可以将多个视图创建在一个类中,但这是由于这个原因,使用viewsets不如单独构建视图那么明确。因此在设计代码时,因通过具体场景选择是使用generic view呢,还是viewsets呢(不过大多数场景下,我还是选择ViewSets)。

  • 相关阅读:
    制作A4纸打印的网页像素大小设置(转)
    关于Vue.use()详解
    Vue的axios如何全局注册
    JS中的apply,call,bind深入理解
    JS异步编程 (2)
    JS异步编程 (1)
    彻底搞清楚javascript中的require、import和export(js模块加载规范的前世今生)
    IPv6地址分类及表示方法
    SublimeText3追踪函数工具CTags设置及使用
    转-编写CGI小结
  • 原文地址:https://www.cnblogs.com/yoyo1216/p/10444125.html
Copyright © 2020-2023  润新知