REST框架包括一個用于處理ViewSets的抽象,它允許開發(fā)人員集中精力對API的狀態(tài)和交互進行建模,并根據(jù)常規(guī)約定自動處理URL構(gòu)造。
ViewSet類與View類幾乎相同,不同之處在于它們提供諸如read或update之類的操作,而不是get或put等方法處理程序。
最后一個ViewSet類只綁定到一組方法處理程序,當(dāng)它被實例化成一組視圖的時候,通常通過使用一個Router類來處理自己定義URL conf的復(fù)雜性。
我們看一下目前的視圖,把它們重構(gòu)成視圖集。
首先讓我們將UserList和UserDetail視圖重構(gòu)為一個UserViewSet。我們可以刪除這兩個視圖,并用一個類替換它們:
from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
此視圖自動提供`list`和`detail`操作。
"""
queryset = User.objects.all()
serializer_class = UserSerializer
這里,我們使用ReadOnlyModelViewSet類來自動提供默認(rèn)的“只讀”操作。我們?nèi)匀幌袷褂贸R?guī)視圖那樣設(shè)置queryset和serializer_class屬性,但我們不再需要向兩個不同的類提供相同的信息。
接下來,我們將替換SnippetList,SnippetDetail和SnippetHighlight視圖類。我們可以刪除三個視圖,并再次用一個類替換它們。
from rest_framework.decorators import detail_route
class SnippetViewSet(viewsets.ModelViewSet):
"""
此視圖自動提供`list`,`create`,`retrieve`,`update`和`destroy`操作。
另外我們還提供了一個額外的`highlight`操作。
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)
@detail_route(renderer_classes=[renderers.StaticHTMLRenderer])
#@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類來獲取完整的默認(rèn)讀寫操作。
請注意,我們還使用@detail_route裝飾器創(chuàng)建一個名為highlight的自定義操作。這個裝飾器可用于添加不符合標(biāo)準(zhǔn)create/update/delete樣式的任何自定義路徑。
默認(rèn)情況下,使用@detail_route裝飾器的自定義操作將響應(yīng)GET請求。如果我們想要一個響應(yīng)POST請求的動作,我們可以使用methods參數(shù)。
默認(rèn)情況下,自定義操作的URL取決于方法名稱本身。如果要更改URL的構(gòu)造方式,可以為裝飾器設(shè)置url_path關(guān)鍵字參數(shù)。
在 Django REST framework 3.8中,使用?
action
?裝飾器替換 ?list_route
?和 ?detail_route
?。 ?list_route
?和 ?detail_route
? 已合并為單個 ?action
?裝飾器。這改進了視圖集操作內(nèi)省,并允許在未來版本中的可瀏覽 API 中顯示額外的操作。?
list_route
?和 ?detail_route
?現(xiàn)在都在等待棄用。它們將在 3.9 中被棄用,并在 3.10 中被完全刪除。新的 ?
action
?裝飾器采用布爾 ?detail
? 參數(shù)。
- 使用?
@action(detail=True)
? 替換 ?detail_route
?。- 使用 ?
@action(detail=False)
? 替換 ?list_route
?。
當(dāng)我們定義URLConf時,處理程序方法只能綁定到那些動作上。 要了解在幕后發(fā)生的事情,首先顯式地從我們的視圖集中創(chuàng)建一組視圖。
在urls.py文件中,我們將ViewSet類綁定到一組具體視圖中。
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'
})
請注意,我們是如何通過將http方法綁定到每個視圖所需的操作,從每個ViewSet類創(chuàng)建多個視圖的。
現(xiàn)在我們將資源綁定到具體的視圖中,我們可以像往常一樣在URL conf中注冊視圖。
urlpatterns = format_suffix_patterns([
url(r'^$', api_root),
url(r'^snippets/$', snippet_list, name='snippet-list'),
url(r'^snippets/(?P<pk>[0-9]+)/$', snippet_detail, name='snippet-detail'),
url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),
url(r'^users/$', user_list, name='user-list'),
url(r'^users/(?P<pk>[0-9]+)/$', user_detail, name='user-detail')
])
因為我們使用的是ViewSet類而不是View類,我們實際上不需要自己設(shè)計URL。將資源連接到視圖和url的約定可以使用Router類自動處理。我們需要做的就是使用路由器注冊相應(yīng)的視圖集,然后讓它執(zhí)行其余操作。
這是我們重寫的urls.py文件。
from django.conf.urls import url, include
from snippets import views
from rest_framework.routers import DefaultRouter
# 創(chuàng)建路由器并注冊我們的視圖。
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)
# API URL現(xiàn)在由路由器自動確定。
# 另外,我們還要包含可瀏覽的API的登錄URL。
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
使用路由器注冊viewsets類似于提供urlpattern。我們包含兩個參數(shù) - 視圖的URL前綴和視圖本身。
我們使用的DefaultRouter類也會自動為我們創(chuàng)建API根視圖,因此我們現(xiàn)在可以從我們的views模塊中刪除api_root方法。
使用視圖集可以是一個非常有用的抽象。它有助于確保URL約定在你的API中保持一致,最大限度地減少編寫所需的代碼量,讓你能夠?qū)W⒂贏PI提供的交互和表示,而不是URLconf的細(xì)節(jié)。
這并不意味著采用視圖集總是正確的方法。在使用基于類的視圖而不是基于函數(shù)的視圖時,有一個類似的權(quán)衡要考慮。使用視圖集不像單獨構(gòu)建視圖那樣明確。
更多建議: