Rest framework 学习(6) ViewSets和路由器

ViewSets: 提供一组操作行为action,例如:list(),retrieve(),create(),update(),destory()等,不再提供get,post方法了。其下多种ModelViewSet能提供更简便的开发方式。

注册路由:自动处理将资源连接到视图和URL的约定。将不同http请求与ViewSets不同方法,一一映射起来。

重构以使用ViewSet

重构我们UserList和UserDetail意见纳入一个单一的UserViewSet。我们可以删除这两个视图,并用一个类替换它们:

# class UserList(generics.ListAPIView):
#     queryset = User.objects.all()
#     serializer_class = UserSerializer
# class UserDetail(generics.RetrieveAPIView):
#     queryset = User.objects.all()
#     serializer_class = UserSerializer

# ViewSets

from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

#  This viewset automatically provides `list` and `detail` actions.

重构SnippetList,SnippetDetail和SnippetHighlight视图类,用一个类替换它们。

# class SnippetList(generics.ListCreateAPIView):
#     queryset = Snippet.objects.all()
#     serializer_class = SnippetSerializer
#     permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
#
#     def perform_create(self, serializer):
#         # 保存之前按,加入owner信息
#         # 通过覆盖我们的代码段视图上的方法,允许我们修改实例保存的管理方式,并处理传入请求或请求的URL中隐含的任何信息。
#         serializer.save(owner=self.request.user)
#
#
# class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
#     queryset = Snippet.objects.all()
#     serializer_class = SnippetSerializer
#     permission_classes = (permissions.IsAuthenticatedOrReadOnly,IsOwnerOrReadOnly)
#
#
# class SnippetHighlight(generics.GenericAPIView):
#     queryset = Snippet.objects.all()
#     renderer_classes = (renderers.StaticHTMLRenderer,)
#
#     def get(self, request, *args, **kwargs):
#         snippet = self.get_object()
#         return Response(snippet.highlighted)

# 修改SnippetList, SnippetDetail and SnippetHighlight,成为一个类
from rest_framework.decorators import action
class SnippetViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.

    Additionally we also provide an extra `highlight` action.
    """
    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请求,我们可以通过@action(method='POST',...) 进行实现构造post请求
  • 默认情况下,自定义操作的URL取决于方法名称本身。如果要更改url的构造方式,可以包含url_pathdecorator关键字参数

将ViewSets明确绑定到URL

这里,我们主要探求ViewSet如何通过将http方法绑定到每个视图所需的操作的。

from snippets.views import SnippetViewSet, UserViewSet, api_root
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'
})

将资源绑定到具体视图中,我们可以像往常一样使用URL conf注册视图。

urlpatterns = format_suffix_patterns([
    path('', api_root),
    path('snippets/', snippet_list, name='snippet-list'),
    path('snippets//', snippet_detail, name='snippet-detail'),
    path('snippets//highlight/', snippet_highlight, name='snippet-highlight'),
    path('users/', user_list, name='user-list'),
    path('users//', user_detail, name='user-detail')
])


# 这里注意,path(route, view, kwargs=None, name=None)参数,view填写上面我们生成的视图

使用路由器

因为我们使用的是ViewSet类而不是View类,所以我们实际上不需要自己设计URL。可以使用Router类自动处理将资源连接到视图和URL的约定。

这是我们的重写snippets/urls.py文件。

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views

# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)

# The API URLs are now determined automatically by the router.
urlpatterns = [
    path('', include(router.urls)),
]

向路由器注册视图集与提供urlpattern类似。我们包括两个参数 - 视图的URL前缀和视图集本身。

我们正在使用的DefaultRouter类也会自动为我们创建api_root根视图,因此我们可以删除掉# snippets/views
模块中的api_root方法而不会有任何影响。

# snippets/views.py
# # 給API_ROOT 添加API 端点
# @api_view(['GET'])
# def api_root(request, format=None):
#     return Response({
#         'users': reverse('user-list', request=request, format=format),
#         'snippets': reverse('snippet-list', request=request, format=format)
#     })

视图与视图集之间的权衡

使用视图集可能是一个非常有用的抽象。它有助于确保URL约定在您的API中保持一致,最大限度地减少您需要编写的代码量,并使您可以专注于API提供的交互和表示,而不是URL conf的细节

但是,使用视图集不如单独构建视图那么明确。

 

你可能感兴趣的:(Django,Rest,Framework)