APIView
類,它是Django的View
類的子類。REST framework主要的幾種view以及他們之間的關係:git
到目前爲止,咱們使用的建立/獲取/更新/刪除操做和咱們建立的任何基於模型的API視圖很是類似。這些常見的行爲是在REST框架的mixin類中實現的github
Mixin 類提供用於提供基本視圖行爲的操做。注意mixin類提供動做方法,而不是直接定義處理程序方法,例如 .get()
和 .post()
, 這容許更靈活的行爲組成。django
Mixin 類能夠從 rest_framework.mixins
導入。json
mixins | 做用 | 對應HTTP的請求方法 |
mixins.ListModelMixin | 定義list方法,返回一個queryset的列表api |
GET |
mixins.CreateModelMixin | 定義create方法,建立一個實例 | POST |
mixins.RetrieveModelMixin | 定義retrieve方法,返回一個具體的實例 | GET |
mixins.UpdateModelMixin | 定義update方法,對某個實例進行更新 | PUT/PATCH |
mixins.DestroyModelMixin | 定義delete方法,刪除某個實例 | DELETE |
APIView對django自己的View進行封裝session
APIView
類和通常的View
類有如下不一樣:框架
被傳入處處理方法的請求不會是Django的HttpRequest
類的實例,而是REST framework的Request
類的實例。ide
處理方法能夠返回REST framework的Response
,而不是Django的HttpRequest
。視圖會管理內容協議,給響應設置正確的渲染器。post
任何APIException
異常都會被捕獲,而且傳遞給合適的響應。ui
進入的請求將會通過認證,合適的權限和(或)節流檢查會在請求被派發處處理方法以前
authentication_classes:用戶登陸認證方式,session或者token等等。
permission_classes:權限設置,是否須要登陸等。
throttle_classes:限速設置,對用戶進行必定的訪問次數限制等等
使用APIView
類和使用通常的View
類很是類似,一般,進入的請求會被分發到合適處理方法好比.get()
,或者.post
。另外,不少屬性會被設定在控制API策略的各類切面的類上。
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import authentication, permissions class ListUsers(APIView): """ 列出系統中的全部用戶的視圖。 * 須要token認證 * 只有管理員用戶能夠訪問這個視圖。 """ authentication_classes = (authentication.TokenAuthentication,) permission_classes = (permissions.IsAdminUser,) def get(self, request, format=None): """ Return a list of all users. """ usernames = [user.username for user in User.objects.all()] return Response(usernames)
該類對APIView進行更高層次的封裝,擴展了REST框架的 APIView
類,爲標準list和detail view 添加了一般須要的行爲。
提供的每一個具體通用視圖是經過將 GenericAPIView
與一個或多個mixin類組合來構建的。
from rest_framework import mixins from rest_framework import generics class CourseListView(mixins.ListModelMixin, generics.GenericAPIView): """ 課程列表頁 """ queryset = Course.objects.all() serialize_class = CourseSerializer def get(self, request, *args, **kwargs): # list方法是存在於mixins中的,同理,create等等也是 # GenericAPIView沒有這些方法! return self.list(request, *args, **kwargs)
上述中,繼承了mixins中的ListModelMixin,就是對應把HTTP的get方法轉換調用list方法,list方法會返回queryset的json數據
GenericAPIView對APIView再次封裝,實現了強大功能:
例如·,獲取具體的某個課程,假設傳進來的URL爲:http://127.0.0.1:8000/course/1/,系統會默認這個1指的是course的id。那麼,如今面臨一個問題,假設我定義了一個用戶收藏的Model,我想要知道我id爲1的主機是否收藏了,我傳進來的URL爲:http://127.0.0.1:8000/userfav/1/,系統會默認獲取userfav的id=1的實例,這個邏輯明顯是錯的,咱們須要獲取course的id=1的收藏記錄,因此咱們就須要用到這個屬性或者重載lookup_field=」course_id」這個方法。
GenericAPIView的不足之處:
既然GenericAPIView以及它相關的View已經完成了許許多多的功能,那麼還要ViewSet幹嗎!
首先,咱們思考一個問題,一樣上面的例子,咱們在功能上,要獲取課程的列表,也要獲取某個課程的具體信息。那麼怎麼實現,按照GenericAPIView,咱們能夠這樣實現:
class CourseView(ListAPIView,RetrieveAPIView): # 只須要在上面的基礎上,再繼承RetrieveAPIView就ok了。 queryset = Course.objects.all() serialize_class = CourseSerializer
GenericViewSet繼承了GenericAPIView,依然有get_queryset,get_serialize_class相關屬性與方法,GenericViewSet重寫了as_view方法,能夠獲取到HTTP的請求方法。
使用ViewSet
類比使用View
類有兩個主要優勢。
queryset
一次,它將在多個視圖中使用。如:上述問題中咱們能夠這樣解決
法一:
from rest_framework import viewsets import... class CourseViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = Course.objects.all() def get_serializer_class(self): # 重寫get_serializer_class方法 if self.action == 'list': return CourseSerializer return CourseDetailSerializer
http請求方法與mixins的方法進行綁定
但GenericViewSet自己依然不存在list, create方法,須要咱們與mixins一塊兒混合使用,那麼新問題來了?咱們依然須要本身寫get、post方法,而後再return list或者create等方法嗎?固然不!重寫as_view的方法爲咱們提供了綁定的功能,咱們在設置url的時候:# 進行綁定 courses = CourseViewSet.as_view({ 'get': 'list', 'post': 'create' }) urlpatterns = [ ... # 常規加入url匹配項 url(r'courses/', CourseViewSet.as_view(), name='courses')]
這樣,咱們就將http請求方法與mixins方法進行了關聯。那麼還有更簡潔的方法嗎?很明顯,固然有,這個時候,route就登場了!
法二:route方法註冊與綁定
由於咱們使用ViewSet類而不是View類,實際上不用本身設計URL conf及綁定HTTP方法。鏈接resources到views和urls的約定可使用Router類自動處理。咱們須要作的僅僅是正確的註冊View到Router中,而後讓它執行其他操做。新的urls.py代碼以下:
from rest_framework.routers import DefaultRouter router = DefaultRouter() # 只須要實現一次 router.register(r'courses', CourseViewSet, base_name='courses') urlpatterns = [ ... # 只須要加入一次 url(r'^', include(router.urls)),]
route中使用的必定要是ViewSet,用router.register的方法註冊url不只能夠很好的管理url,不會致使url過多而混亂,並且還能實現http方法與mixins中的相關方法進行鏈接。
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet): # 知足只有GET方法請求的情景 pass class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): # 知足全部請求都有的情景 pass
在開發的時候,直接繼承 viewsets.ModelViewSet 就能夠了,這樣就不用寫list、create、update等方法了,固然具體問題具體分析,若是你的需求與DRF提供的不一致,那麼你就能夠重寫相應的方法便可
假若有這樣一個需求,你可能須要過濾查詢集,以確保只返回與當前經過身份驗證的用戶發出的請求相關的結果。
class CourserViewSet(ModelViewSet): """ 每一個用戶只能夠查看owner屬於本身的條目,能夠建立條目 """ def list(self, request, *args, **kwargs): self.queryset = Course.objects.filter(owner=request.user.id) self.serializer_class = CourseSerializer return super(CourserViewSet, self).list(request, *args, **kwargs) def create(self, request, format=None): serializer = CourseSerializer(data=request.data) if serializer.is_valid(): # .save()是調用CourseSerializer中的create()方法 serializer.save(owner=self.request.user) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
這裏定義了兩個方法,list方式中咱們咱們重寫了queryset(就是對返回結果作了一次過濾),而後對於serializer_class指定了一個序列化類。而且咱們使用super方法,繼續載入viewset中的list方法,這裏只會覆蓋原有list的queryset和serializer_class。而對於create方法,咱們則是徹底重寫了原viewset中的create方法。這裏只是演示一下再ViewSet模式下如何來作工做。原則就是能用ViewSet內置的就是用內置的,內置的不知足需求就能夠重寫部分或所有重寫。
另外,若是隻是過濾查詢集,最簡單方法是重寫.get_queryset()
方法便可。重寫此方法容許你以多種不一樣方式自定義視圖返回的查詢集。
class CourseViewSet(ModelViewSet): """ 每一個用戶只能夠查看owner屬於本身的條目,能夠建立條目 """ serializer_class = CourseSerializer def list(self, request, *args, **kwargs): return Course.objects.filter(owner=request.user.id)
create
,list
和retrieve
操做,繼承GenericViewSet
和混入所需的操做:
class CreateListRetrieveViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ A viewset that provides `retrieve`, `create`, and `list` actions. To use it, override the class and set the `.queryset` and `.serializer_class` attributes. """ pass
ps:在開發時是使用ViewSet與mixins方法結合進行能夠爲咱們節省不少功夫
參考:
https://q1mi.github.io/Django-REST-framework-documentation/api-guide/generic-views_zh/
https://www.django-rest-framework.org/api-guide/viewsets/
http://www.ywnds.com/?p=14104