其實,與其使用基于方法(function based)的視圖,我們更加傾向使用基于類(class based)的視圖。接下來,你將看到這是一個強大的模式,是我們能夠重用公共的功能,并且,幫我們保持代碼DRY。
使用基于類的視圖 重寫我們的API
我們現在開始了。首先,重寫根視圖(root view),變成基于類的視圖。所涉及的,只是對?views.py文件的一點重構。
from?snippets.models?import?Snippet
from?snippets.serializers?import?SnippetSerializer
from?django.http?import?Http404
from?rest_framework.views?import?APIView
from?rest_framework.response?import?Response
from?rest_framework?import?status
class?SnippetList(APIView):
????#?APIView實際繼承django總的View
????#?from?django.views.generic?import?View
????"""
????#?這里是SnippetList接口描述
????List?all?snippets,?or?create?a?new?snippet.
????"""
????def?get(self,?request,?format=None):
????????snippets?=?Snippet.objects.all()
????????#?manay=True?用于querySet對象
????????serializer?=?SnippetSerializer(snippets,?many=True)
????????3?Respone比django的response更強大
????????return?Response(serializer.data)
????def?post(self,?request,?format=None):
????????serializer?=?SnippetSerializer(data=request.data)
????????if?serializer.is_valid():
????????????#?.save()是調用SnippetSerializer中的create()方法
????????????serializer.save()
????????????return?Response(serializer.data,?status=status.HTTP_201_CREATED)
????????return?Response(serializer.errors,?status=status.HTTP_400_BAD_REQUEST)
至此為止,一切順利??雌饋?,跟之前的案例差別不大,但我們將各個HTTP請求方法之間,做了更好的分離。接著,我們將同樣的更改我們,處理片段詳細的視圖,繼續我們的?views.py?文件:。
class?SnippetDetail(APIView):
????"""
????讀取,?更新?or?刪除一個代碼片段(snippet)實例(instance).
????"""
????def?get_object(self,?pk):
????????try:
????????????return?Snippet.objects.get(pk=pk)
????????except?Snippet.DoesNotExist:
????????????raise?Http404
????def?get(self,?request,?pk,?format=None):
????????snippet?=?self.get_object(pk)
????????serializer?=?SnippetSerializer(snippet)
????????return?Response(serializer.data)
????def?put(self,?request,?pk,?format=None):
????????snippet?=?self.get_object(pk)
????????serializer?=?SnippetSerializer(snippet,?data=request.data)
????????if?serializer.is_valid():
????????????serializer.save()
????????????return?Response(serializer.data)
????????return?Response(serializer.errors,?status=status.HTTP_400_BAD_REQUEST)
????def?delete(self,?request,?pk,?format=None):
????????snippet?=?self.get_object(pk)
????????snippet.delete()
????????return?Response(status=status.HTTP_204_NO_CONTENT)
這看起來不錯。 同樣,它現在仍然非常像基于方法的視圖。
我們還需要稍微重構我們的snippets/urls.py,因為我們正在使用基于類的視圖。
from?django.conf.urls?import?url
from?rest_framework.urlpatterns?import?format_suffix_patterns
from?snippets?import?views
urlpatterns?=?[
????url(r'^snippets/$',?views.SnippetList.as_view()),
????url(r'^snippets/(?P[0-9]+)/$',?views.SnippetDetail.as_view()),
]
urlpatterns?=?format_suffix_patterns(urlpatterns)
好的,我們完成了。 如果你運行開發服務器,一切都應該像以前一樣工作。
使用混入mixins
使用基于類的視圖的好處是,我們可以很容易組成可重復使用的代碼。
到目前為止,我們使用的創建/檢索/更新/刪除操作,對于我們創建的,任何模型支持的API視圖將非常相似。 這些常見的行為是在REST框架的mixin類中都已經實現的。
我們來看看如何使用mixin類來構建視圖。 這是我們的views.py模塊了。
from?snippets.models?import?Snippet
from?snippets.serializers?import?SnippetSerializer
from?rest_framework?import?mixins
from?rest_framework?import?generics
class?SnippetList(mixins.ListModelMixin,
??????????????????mixins.CreateModelMixin,
??????????????????generics.GenericAPIView):
????#?mixins.CreateModelMixin?可以保存數據??????????????????
????#?generics.GenericAPIView?繼承了APIView
????queryset?=?Snippet.objects.all()
????serializer_class?=?SnippetSerializer
????def?get(self,?request,?*args,?**kwargs):
????????#?self.list是ListModelMixin的list函數
????????#?功能是過濾、分頁、調用serializer,將數據序列化
????????return?self.list(request,?*args,?**kwargs)
????def?post(self,?request,?*args,?**kwargs):
????????return?self.create(request,?*args,?**kwargs)
我們將花一點時間仔細檢查這里發生的事情。我們用GenericAPIView建一個視圖,并添加ListModelMixin和CreateModelMixin。
?到目前為止足夠簡單?;愄峁┖诵墓δ埽琺ixin類提供.list()和.create()操作。然后,我們明確的將get和post方法綁定到適當的操作上。
class?SnippetDetail(mixins.RetrieveModelMixin,
????????????????????mixins.UpdateModelMixin,
????????????????????mixins.DestroyModelMixin,
????????????????????generics.GenericAPIView):
????queryset?=?Snippet.objects.all()
????serializer_class?=?SnippetSerializer
????def?get(self,?request,?*args,?**kwargs):
????????return?self.retrieve(request,?*args,?**kwargs)
????def?put(self,?request,?*args,?**kwargs):
????????return?self.update(request,?*args,?**kwargs)
????def?delete(self,?request,?*args,?**kwargs):
????????return?self.destroy(request,?*args,?**kwargs)
很相似,我們再次使用GenericAPIView類來提供核心功能,并在mixin中添加.retrieve(),.update()和.destroy()方法。
使用通用的基于類的視圖
使用mixin類,我們重寫了視圖,使用比以前稍少的代碼,但是我們可以更進一步。 REST框架提供了一組已經混合的通用視圖,我們可以使用這些通用視圖來重構我們的views.py模塊。
from?snippets.models?import?Snippet
from?snippets.serializers?import?SnippetSerializer
from?rest_framework?import?generics
class?SnippetList(generics.ListCreateAPIView):
????queryset?=?Snippet.objects.all()
????serializer_class?=?SnippetSerializer
class?SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
????queryset?=?Snippet.objects.all()
????serializer_class?=?SnippetSerializer
哇,這很簡潔。我們的代碼看起來非常優雅。
接下來,我們將介紹本教程的第4部分,在這里我們將看看如何處理我們的API的身份驗證和權限。