drf之视图集

一、为什么要有视图集

​ 我们使用drf提供的generics包可以很轻松的实现六大基础接口,但我们会发现群查和单查却无法共存。这是由于我们寄希望于继承generics.ListAPIView来实现群查,同时有希望继承generics.RetrieveAPIView来实现单查,但由于继承顺序的关系,群查和单查并不能共存。

我们希望在访问 群查或单查的接口时,可以有另外一种映射关系。

""" ViewSetMixin类存在理由推到
1)工具视图类,可以完成应付六大基础接口,唯一缺点是单查与群查接口无法共存
	(只配置queryset、serializer_class、lookup_field)
2)不能共存的原因:RetrieveAPIView和ListAPIView都是get方法,不管带不带pk的get请求,只能映射给一个get方法
3)能不能修改映射关系:
	比如将/books/的get请求映射给list方法,
	将/books/(pk)/的get请求映射给retrieve方法,
	甚至可以随意自定义映射关系
"""

二、视图集

ViewSetMixin类是视图集的基类。它重写了as_view方法,rest_framework.viewsets下的类都间接或直接的继承了它,所以都会继承它的方法。

源码分析
def as_view(cls, actions=None, **initkwargs):
	'''.......'''
    # 必须提供actions
    if not actions:
        raise TypeError('....')
        
	'''........'''
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        self.action_map = actions
        # {'get':'list'}获取请求方式method--->映射方法list
        for method, action in actions.items():
            handler = getattr(self, action)
            # 修改了映射get-->list
            setattr(self, method, handler)

        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get

        self.request = request
        self.args = args
        self.kwargs = kwargs

        # 还是由dispatch进行分发
        return self.dispatch(request, *args, **kwargs)
    view.cls = cls
    view.initkwargs = initkwargs
    view.actions = actions
    return csrf_exempt(view)
urls.py

我们看urls.py中的变化再看as_view的源码,两条url的as_view的actions参数是不一样的。

# 群查接口的as_view的actions
url(r'^v3/books/$', views.BookV3APIView.as_view(
    {'get': 'list', 'post': 'create'}
	)),

# 单查接口的as_view的actions
url(r'^v3/books/(?P<pk>\d+)/$', views.BookV3APIView.as_view(
        {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}
    )),
views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
class BookV3APIView(ModelViewSet):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer

可以在ModelViewSet的源码中看到继承了一系列generic包下的一系列类。我们可以借用它直接完成六大接口!

三、路由组件

可以看到as_view中自己配置的actions的对应关系也比较繁琐,drf还为我们提供了路由组件,来配合视图集使用(路由组件不能单独存在,必须配合视图集使用)

urls.py
from django.conf.urls import url, include
from . import views
# 路由组件,必须配合视图集使用
from rest_framework.routers import SimpleRouter
router = SimpleRouter()

# 以后就写视图集的注册即可:BookV3APIView和BookV4APIView都是视图集
router.register('v3/books', views.BookV3APIView, 'book')
router.register('v4/books', views.BookV4APIView, 'book')

urlpatterns = [
    url('', include(router.urls))
]
views.py
from rest_framework.viewsets import ReadOnlyModelViewSet
class BookV4APIView(ReadOnlyModelViewSet):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer

四、自定义路由组件

router.py
from rest_framework.routers import SimpleRouter as DrfSimpleRouter
from rest_framework.routers import Route, DynamicRoute

class SimpleRouter(DrfSimpleRouter):
    routes = [
        # List route.
        Route(
            url=r'^{prefix}{trailing_slash}$',
            mapping={
                'get': 'list',
                'post': 'create',  # 注:群增只能自己在视图类中重写create方法,完成区分
                'delete': 'multiple_destroy',  # 新增:群删
                'put': 'multiple_update',  # 新增:群整体改
                'patch': 'multiple_partial_update'  # 新增:群局部改
            },
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        # Dynamically generated list routes. Generated using
        # @action(detail=False) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=False,
            initkwargs={}
        ),
        # Detail route.
        Route(
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            },
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
        # Dynamically generated detail routes. Generated using
        # @action(detail=True) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=True,
            initkwargs={}
        ),
    ]
posted @ 2020-02-25 18:58  GhostAnt  阅读(178)  评论(0编辑  收藏  举报