ViewSets & Routers
https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/
ViewSets是对模型的高度抽象, 让开发者聚焦于建模状态, 和 接口的交互, 基于通用的规则构建URL.
REST framework includes an abstraction for dealing with
ViewSets
, that allows the developer to concentrate on modeling the state and interactions of the API, and leave the URL construction to be handled automatically, based on common conventions.
ViewSet
classes are almost the same thing asView
classes, except that they provide operations such asretrieve
, orupdate
, and not method handlers such asget
orput
.A
ViewSet
class is only bound to a set of method handlers at the last moment, when it is instantiated into a set of views, typically by using aRouter
class which handles the complexities of defining the URL conf for you.
Refactoring to use ViewSets
定义非常简单,无需关注 get post接口。
Here we've used the
ReadOnlyModelViewSet
class to automatically provide the default 'read-only' operations. We're still setting thequeryset
andserializer_class
attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes.
from rest_framework import viewsets class UserViewSet(viewsets.ReadOnlyModelViewSet): """ This viewset automatically provides `list` and `retrieve` actions. """ queryset = User.objects.all() serializer_class = UserSerializer
可以自定义action。
This time we've used the
ModelViewSet
class in order to get the complete set of default read and write operations.Notice that we've also used the
@action
decorator to create a custom action, namedhighlight
. This decorator can be used to add any custom endpoints that don't fit into the standardcreate
/update
/delete
style.Custom actions which use the
@action
decorator will respond toGET
requests by default. We can use themethods
argument if we wanted an action that responded toPOST
requests.
from rest_framework.decorators import action from rest_framework.response import Response from rest_framework import permissions 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)
Binding ViewSets to URLs explicitly
对于一个viewsets可以定义多个视图。
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
urlpatterns = format_suffix_patterns([ path('', api_root), 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') ])
Using Routers
使用router进行注册。
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)), ]
Trade-offs between views vs viewsets
保证API一致性
减少书写的代码
使得你聚焦于API交互和表示
Using viewsets can be a really useful abstraction. It helps ensure that URL conventions will be consistent across your API, minimizes the amount of code you need to write, and allows you to concentrate on the interactions and representations your API provides rather than the specifics of the URL conf.
That doesn't mean it's always the right approach to take. There's a similar set of trade-offs to consider as when using class-based views instead of function based views. Using viewsets is less explicit than building your views individually.
View继承图
https://testdriven.io/blog/drf-views-part-3/
https://mrcoles.com/django-rest-framework-abstraction-grid/
Django REST Framework Views Series:
https://testdriven.io/blog/drf-views-part-1/
https://testdriven.io/blog/drf-views-part-2/
https://testdriven.io/blog/drf-views-part-3/