REST框架包含要一个用于处理的抽象ViewSets,允许开发人员专注于建模API的状态和交互,并使用URL构造基于通用约定自动处于。
ViewSet类几乎与View类相同,除了它们提供诸如read或update之类的操作,而不是诸如get或者put之类的方法处理程序。
最后一个ViewSet类只绑定到一组方法处理程序,当它被实例化成一组视图的时候,通常通过使用一个Router类来处理自己定义的URLconf的复杂性。

使用ViewSets重构

将UserList和UserDetail视图重构为一个UserViewSet。

from rest_framework import viewsets

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    自动提供list和detail操作
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

ReadOnlyModelViewSet类自动提供默认的只读操作。我们仍然像使用常规视图时那样设置request和serializer_calss属性,但我们不再需要向两个单独的类提供相同的信息。
同样的SnippetList,SnippetDetail和SnippetHighlight视图也可以整合在同一个视图中。

class SnippetViewSet(viewsets.ModelViewSet):
    """
    此视图自动提供list, create, retrieve, update 和 destroy 操作
    另外我们还提供了一个额外的highlight的操作
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]

    @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

ModelViewSet获得完整的默认读写操作集。
注意,这个视图中我们还是用@action装饰器来创建名为highlight的自定义操作。此装饰器用于添加任何不适合标准create/update/delete样式的自定义路由
默认情况下,使用@action装饰器的自定义操作将相应GET请求。如果我们想要一个相应POST请求的动作,可以使用methods参数。
默认情况下,自定义操作的URL取决于方法名称本身。如果要更改url构造方式,可以为装饰器设置url_path关键字参数。

将ViewSets绑定到URL

处理程序方法尽在定义URLconf时绑定到操作,要了解幕后发生了什么,我们首先要从ViewSets中明确创建一组视图。

# snippets/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets.views import SnippetViewSet, UserViewSet
from rest_framework import renderers

snippet_list = SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
snippet_detail = SnippetViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})
snippet_highlight = SnippetViewSet.as_view({
    'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])
user_list = UserViewSet.as_view({
    'get': 'list'
})
user_detail = UserViewSet.as_view({
    'get': 'retrieve'
})
urlpatterns = format_suffix_patterns([
    path('snippets/', snippet_list, name='snippet-list'),
    path('snippets/<int:pk>/', snippet_detail, name='snippet-detail'),
    path('snippets/<int:pk>/highlight/', snippet_highlight, name='snippet-highlight'),
    path('users/', user_list, name='user-list'),
    path('users/<int:pk>/', user_detail, name='user-detail')
])

使用路由器

因为我们使用的是ViewSet类而不是View类,所以实际上不需要自己设计URL。可以使用Router类自动处理将资源链接到视图和URL的约定。我们需要做的就是用路由器注册适当的视图集,然后让它完成剩下的操作。

# snippets/urls.py
from django.urls import path
from django.conf.urls import include
from rest_framework.routers import DefaultRouter
from snippets import views

router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)

urlpatterns = [
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('', include(router.urls)),
]

想路由器注册视图与提供urlpattern类似,我们包含两个参数:视图的URL前缀和视图本身。
我们使用的DefaultRouter类也会自动为我们创建API根视图,因此现在可以从views模块中删除api_root方法。

视图和视图集之间的权衡

使用视图集可以是一个非常有用的抽象。它将助于确保URL约定在API中保持一直,最大限度地减少编写所需的代码量,让你能够专注于API提供的交互和表示,而不是URLconf的细节。
但是这并不也为这采用视图集总是正确的方法,在使用基于类的视图而不是基于函数的视图时,有一个类似的权衡要考虑。

0条评论

相关推荐

django教程

r

Django 2019-05-20 10:53:53

Celery

celery学习资料

Django 2019-05-25 18:41:55

django教程入门

适合django新人使用的学习手册

Django 2019-07-01 14:28:04

django实用资料

django项目从0到1自己总结的实用的资料,大部分常用的功能这里都有

Django 2019-05-08 18:21:34