美文网首页Python
django的viewSet笔记

django的viewSet笔记

作者: 陈卧虫 | 来源:发表于2018-10-30 17:07 被阅读438次

ViewSet: 视图集

作用: 做整合, 解决查询资源时, 单个和多个资源的整合问题

现在我们定义一个视图, 用于查询书籍的数据

单个数据的类视图

class BookListAPIView(mixins.ListModelMixin, GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    
    
    def get(self,  request, pk):  # 包含一个 PK
        return self.list( request, pk)  # 其实应该是args, kwargs, 只是想突出 PK 才这么写

多个数据的类视图

class BookDetailAPIView(mixins.RetrieveModelMixin, GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    
    def get(self,  request):
        return self.retrieve( request )  # 应该还有 *args, **kwargs

urls.py

urlpatterns = [
    url(r'books/$', views.BookListAPIView.as_view()),
    url(r'books/(?P<pk>\d+)/$', views.BookDetailAPIView.as_view()),
]

是不是很麻烦, 针对同个资源的查询, 只是数量不同, 却需要定义两个不同的类视图, 太过冗余

所以为了解决这个问题,视图集出现了, 它的作用就是将对同一资源的不同请求方式整合到一个视图当中.

使用视图集

class BookInfoViewSet(viewsets.ViewSet):

    def list(self, request):
        ...

    def retrieve(self, request, pk=None):
        ...

urls.py

urlpatterns = [
    url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
    url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
]

ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action , 通过as_view方法
将请求方式与行为(actions)的映射进行完成

这种映射是通过重写as_view()方法实现的

class ViewSetMixin(object):
    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):
        
        if not actions:  # 如果没有传递actions参数,就会报错
            raise TypeError("...")
        
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            self.action_map = actions  # action= {'get': 'list', 'post': 'update'}
            # 对字典actions ,进行映射
            # 比如{'get':'list'}
            # 就会拿到实例的 list方法,添加(或替换)掉get方法
            
            for method, action in actions.items():  # 遍历actions中的所有方法
                handler = getattr(self, action)  # 取出视图里定义的函数的内存地址
                setattr(self, method, handler)  # 为该类视图设置新的属性,或者说添加新的方法, 这个方法的名字就是 method
                # 在调用get方法的时候,实际上调用了list方法
            return self.dispatch(request, *args, **kwargs)  # 调用dispatch 让子类 使用 dispatch找到 请求方式对应的方法
        
        return csrf_exempt(view)  # 返回这个函数

视图集中附加action的方法

通过action装饰器

  • methods: 该action支持的请求方式,列表传递
  • detail: 表示是action中要处理的资源的对象的数量(即是否通过url路径获取主键)
    • True 表示使用通过URL获取的主键, 即是单个数据对象
    • False 表示不使用URL获取主键, 即获取的是一组数据对象

举例:

views.py

from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    # detail为False 表示不需要处理具体的BookInfo对象
    @action(methods=['get'], detail=False)
    def latest(self, request):
        """
        返回最新的图书信息
        """
        book = BookInfo.objects.latest('id')
        serializer = self.get_serializer(book)
        return Response(serializer.data)

    # detail为True,表示要处理具体与pk主键对应的BookInfo对象
    @action(methods=['put'], detail=True)
    def read(self, request, pk):
        """
        修改图书的阅读量数据
        """
        book = self.get_object()
        book.bread = request.data.get('read')
        book.save()
        serializer = self.get_serializer(book)
        return Response(serializer.data)

urls.py

urlpatterns = [
    url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
    url(r'^books/(?P<pk>\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
    
    # 没有pk的, 代表访问的的是多个资源,一组数据, 所以detail应该为False
    url(r'^books/latest/$', views.BookInfoViewSet.as_view({'get': 'latest'})),
    # 有pk的, 代表访问的的是单个资源, 所以detail应该为True
    url(r'^books/(?P<pk>\d+)/read/$', views.BookInfoViewSet.as_view({'put': 'read'})),
]

Router路由的定义

上面的url的是不是太麻烦了, 可能感觉不出来, 因为只有4种请求方式, 但如果有100种呢, 是不是需要定义100个url,

太麻烦了, 所以引入router, 目的只有一个: 简化/省略 url的配置

  • 内置两个可用的路由
    • SimpleRouter
    • DefaultRouter (继承自SimpleRouter, 在它的基础上添加了对根路由的支持)
  • 使用方法

创建router对象,并注册视图集

from rest_framework import routers


router = routers.SimpleRouter()
router.register(r'books', BookInfoViewSet, base_name='book')

register(prefix, viewset, base_name)

  • prefix 该视图集的路由前缀
  • viewset 视图集
  • base_name 路由名称的前缀

如上述代码会形成的路由如下:

^books/$    name: book-list
^books/{pk}/$   name: book-detail

^books/latest/$    name: book-latest
^books/{pk}/read/$  name: book-read

添加路由数据

可以有两种方式:

urlpatterns = [
    ...
]
urlpatterns += router.urls

urlpatterns = [
    ...
    url(r'^', include(router.urls))
]

相关文章

网友评论

    本文标题:django的viewSet笔记

    本文链接:https://www.haomeiwen.com/subject/ypbgtqtx.html