django-rest-framework学习之路-7-视图集和路由器
1、合并list与detail
我们之前都是两个视图类来表示一组操作,比如SnippetList和SnippetDetail,我们可以合二为一
使用ViewSets类来完成合二为一,称之为视图集
重写snippets/views.py
使用UserViewSet类替换UserList和UserDetail
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
此视图自动提供`list`和`detail`操作。
"""
queryset = User.objects.all()
serializer_class = UserSerializer
继承ReadOnlyModelViewSet,表示只读
使用SnippetViewSet替换SnippetList,SnippetDetail和SnippetHighlight
from django.contrib.auth.models import User
from rest_framework import permissions, renderers, viewsets
from rest_framework.decorators import api_view, action
from rest_framework.response import Response
from rest_framework.reverse import reverse
from snippets.models import Snippet
from snippets.permissions import IsOwnerOrReadOnly
from snippets.serializers import SnippetSerializer, UserSerializer
@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),
})
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
此视图自动提供`list`和`detail`操作。
"""
queryset = User.objects.all()
serializer_class = UserSerializer
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)
使用action装饰器自定义操作,detail=True表示detail方式
提示:ViewSet类与View类几乎相同,不同之处在于它们提供诸如read或update之类的操作,而不是get或put等方法处理程序。
因为ViewSet类是提供read,update之类的方式操作数据,而不是get,put等方式,因此我们的路由就需要改变一下,填充一下对应请求方式对应的处理函数
在snippets/views.py添加对应关系
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'
})
所以snippets/views.py变成了
from django.contrib.auth.models import User
from rest_framework import permissions, renderers, viewsets
from rest_framework.decorators import api_view, action
from rest_framework.response import Response
from rest_framework.reverse import reverse
from snippets.models import Snippet
from snippets.permissions import IsOwnerOrReadOnly
from snippets.serializers import SnippetSerializer, UserSerializer
@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),
})
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
此视图自动提供`list`和`detail`操作。
"""
queryset = User.objects.all()
serializer_class = UserSerializer
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)
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'
})
那对应的路由就改变了
所以snippets/urls.py变成了
from django.urls import re_path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
re_path(r'^$', views.api_root),
re_path(r'^snippets/$', views.snippet_list, name='snippet-list'),
re_path(r'^snippets/(?P[0-9]+)/$', views.snippet_detail, name='snippet-detail'),
re_path(r'^snippets/(?P[0-9]+)/highlight/$', views.snippet_highlight, name='snippet-highlight'),
re_path(r'^users/$', views.user_list, name='user-list'),
re_path(r'^users/(?P[0-9]+)/$', views.user_detail, name='user-detail')
]
urlpatterns = format_suffix_patterns(urlpatterns)
打开浏览器,和之前是一样的效果
使用路由
因为我们使用了ViewSet类而不是View类,既然它可以把list和detail合二为一,那么路由也有简单的处理方式,而不是这么麻烦
我们可以使用router路由器来直接完成对应关系
所以snippets/urls.py变成了
from django.conf.urls import include
from django.urls import re_path
from rest_framework.routers import DefaultRouter
from snippets import views
# 创建路由器并注册我们的视图。
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)
# API URL现在由路由器自动确定。
urlpatterns = [
re_path(r'^', include(router.urls)),
]
视图(views)vs视图集(viewsets)之间的权衡
使用视图集可以是一个非常有用的抽象。它有助于确保URL约定在你的API中保持一致,最大限度地减少编写所需的代码量,让你能够专注于API提供的交互和表示,而不是URLconf的细节。
这并不意味着采用视图集总是正确的方法。在使用基于类的视图而不是基于函数的视图时,有一个类似的权衡要考虑。使用视图集不像单独构建视图那样明确。
学习链接: https://www.w3cschool.cn/lxraw/lxraw-9gjo35og.html