REST框架包括一個處理的抽象ViewSets,它容許開發人員集中精力對API的狀態和交互進行建模,並根據常規約定使URL構造自動處理。html
ViewSet類是幾乎一樣的事情View類,但他們提供諸如操做read,或者update,而不是方法處理,如get或put。django
一個ViewSet類在最後一刻被綁定到一組方法處理程序,當它被實例化成一組視圖時,一般經過使用一個Router類來處理爲你定義URL conf的複雜性。segmentfault
重構使用ViewSets
咱們來看一下咱們目前的觀點,並把它們重構成視圖集。api
首先,讓咱們來重構咱們UserList和UserDetail意見歸入一個單一的UserViewSet。咱們能夠刪除這兩個視圖,並將其替換爲單個類:框架
from rest_framework import viewsets class UserViewSet(viewsets.ReadOnlyModelViewSet): """ This viewset automatically provides `list` and `detail` actions. """ queryset = User.objects.all() serializer_class = UserSerializer
在這裏,咱們使用ReadOnlyModelViewSet該類來自動提供默認的「只讀」操做。咱們仍然正如咱們使用常規視圖同樣設置queryset和serializer_class屬性,可是咱們再也不須要向兩個不一樣的類提供相同的信息。ide
接下來咱們要更換SnippetList,SnippetDetail和SnippetHighlight視圖類。咱們能夠刪除三個視圖,並再次替換爲單個類。函數
from rest_framework.decorators import detail_route 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,) @detail_route(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類來獲取完整的默認讀寫操做。工具
請注意,咱們還使用@detail_route裝飾器建立一個名爲的自定義操做highlight。此裝飾器可用於添加不適合標準create/ update/ delete樣式的任何自定義端點。post
默認狀況下,使用@detail_route裝飾器的自定義操做將響應GET請求。methods若是咱們想要一個響應POST請求的動做,咱們可使用該參數。url
默認狀況下,自定義操做的URL取決於方法名稱自己。若是要更改url應該構造的方式,能夠將url_path做爲decorator的關鍵字參數。
明確地將ViewSets綁定到URL
當咱們定義URLConf時,處理程序方法只會被綁定到動做上。看看發生什麼事情,讓咱們首先從ViewSets中明確建立一組視圖。
在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' })
請注意,咱們如何ViewSet經過將http方法綁定到每一個視圖所需的操做,從每一個類建立多個視圖。
如今咱們將資源綁定到具體的視圖中,咱們能夠像往常同樣使用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類,咱們實際上不須要設計本身的URL。將資源鏈接到視圖和網址的約定可使用Router類自動處理。咱們須要作的就是使用路由器註冊相應的視圖集,而後讓它執行其他操做。
這是咱們的從新連線的urls.py文件。
from django.conf.urls import url, include from snippets import views from rest_framework.routers import DefaultRouter # 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. # Additionally, we include the login URLs for the browsable API. urlpatterns = [ url(r'^', include(router.urls)), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) ]
與路由器註冊視圖與提供urlpattern相似。咱們包括兩個參數 - 視圖的URL前綴和視圖自己。
DefaultRouter咱們使用的類也會自動爲咱們建立API根視圖,所以咱們如今能夠api_root從咱們的views模塊中刪除該方法。
視圖vs視圖之間的權衡
使用視圖能夠是一個很是有用的抽象。它有助於確保您的API中的URL約定是一致的,最大限度地減小您須要編寫的代碼量,並容許您專一於API提供的交互和表示,而不是URL conf的具體內容。
這並不意味着老是採起正確的方法。在使用基於類的視圖而不是基於函數的視圖時,須要考慮一組相似的權衡。使用viewsets比單獨構建視圖不太明確。
在本教程的第7部分中,咱們將介紹如何添加API模式,並使用客戶端庫或命令行工具與API進行交互。
Django REST FrameWork中文文檔目錄:
Django REST FrameWork 中文教程1:序列化
Django REST FrameWork 中文教程2:請求和響應
Django REST FrameWork 中文教程3:基於類的視圖
Django REST FrameWork 中文教程4:驗證和權限
Django REST FrameWork 中文教程5:關係和超連接API