django rest framework apiview、viewset總結分析

引言

  官方文檔:http://www.django-rest-framework.org/
  drf爲咱們提供強大的通用view的功能,本博客對這些view進行簡要的總結分析。
  首先,咱們看一下主要的幾種view以及他們之間的關係。python

view

    這其中,還涉及了mixins,主要也分爲5類: mixins 下面咱們以課程(course)做爲一個例子,對view進行一個總結。django

1. django View

  首先,咱們使用django自帶的view,獲取一個課程的列表:json

# drf是經過json的格式進行數據交互的,因此這裏也返回json數據
import json
from django.views.generic.base import View
from django.core import serializers
from django.http import HttpResponse,JsonResponse
from .models import Course

class CourseListView(View):
    def get(self, request):
        """ 經過django的view實現課程列表頁 """
        courses = Course.objects.all()[:10]
        json_data = serializers.serialize('json', Courses)
        json_data = json.loads(json_data)
        return JsonResponse(json_data, safe=False)
複製代碼

2. APIView

接下來,咱們用APIView來實現bash

from rest_framework.views import APIView
from rest_framework.response import Response
# 這個serializers是在其餘文件自定義的,這裏對這個不進行過多介紹
from .serializers import CourseSerializer

class CourseListView(APIView):
    def get(self, request, format=None):
        """ 經過APIView實現課程列表頁 """
        courses = Course.objects.all()
        serializer = CourseSerializer(courses, many=True)
        return Response(serializer.data)
複製代碼

  在APIView這個例子中,調用了drf自己的serializer以及Response方法。
  APIView對django自己的View進行封裝,從上述的代碼,這樣分析,二者的差異看起來不是很大,但實際中APIView作了不少東西,它定義了不少屬性與方法,舉幾個例子session

# 這三個是經常使用的屬性
    authentication_classes : 用戶登陸認證方式,session或者token等等
    permission_classes : 權限設置,是否須要登陸等
    throttle_classes : 限速設置,對用戶進行必定的訪問次數限制等等。
複製代碼

  到這裏,可能還不能體現drf經過view的強大之處,那麼接下來的GenericAPIView就展現了它強大的功能。post

3. GenericAPIView

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,在get( )方法中,調用了它的list()方法,list方法會返回queryset的json數據。這裏對mixins不進行過多的介紹。 GenericAPIView對APIView再次封裝,實現了強大功能:ui

  • 加入queryset屬性,能夠直接設置這個屬性,沒必要再將實例化的courses,再次傳給seriliazer,系統會自動檢測到。除此以外,能夠重載get_queryset(),這樣就沒必要設置'queryset=*',這樣就變得更加靈活,能夠進行徹底的自定義。
  • 加入serializer_class屬性與實現get_serializer_class()方法。二者的存在一個便可,經過這個,在返回時,沒必要去指定某個serilizer
  • 設置過濾器模板:filter_backends
  • 設置分頁模板:pagination_class
  • 加入 lookup_field="pk",以及實現了get_object方法:這個用得場景很少,但十分重要。它們二者的關係同1,要麼設置屬性,要麼重載方法。它們的功能在於獲取某一個實例時,指定傳進來的後綴是什麼。
       舉個例子,獲取具體的某個課程,假設傳進來的ulr爲: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"。
       在generics除了GenericAPIView還包括了其餘幾個View: CreateAPIView、ListAPIView、RetrieveAPIView、ListCreateAPIView···等等,其實他們都只是繼承了相應一個或多個mixins和GenericAPIView,這樣,有什麼好處?咱們看一下一樣一個例子的代碼:
class CourseListView(ListAPIView):
	""" 課程列表頁 """
 	queryset = Course.objects.all()
 	serialize_class = CourseSerializer
複製代碼

  這樣,就完成了和剛剛如出一轍的功能!url

4.GenericViewSet

  • GenericAPIView的不足之處

  既然GenericAPIView以及它相關的View已經完成了許許多多的功能,那麼還要ViewSet幹嗎!
  首先,咱們思考一個問題,一樣上面的例子,咱們在功能上,要獲取課程的列表,也要獲取某個課程的具體信息。那麼怎麼實現,按照GenericAPIView,咱們能夠這樣實現:spa

class CourseView(ListAPIView,RetrieveAPIView):
 	# 只須要在上面的基礎上,再繼承RetrieveAPIView就ok了。
 	queryset = Course.objects.all()
 	serialize_class = CourseSerializer
 	
複製代碼

  但這樣實現有一個問題,關於serialize_class,顯然,當獲取課程列表時,只須要傳回去全部課程的簡要信息,如課程名字,老師,封面等等,但當獲取課程的具體信息,咱們還要將他們的章節以及相關下載資料(很明顯,章節是另一個model,有一個外鍵指向course),這些信息會不少,在獲取課程列表,將這些傳回去顯然是不理智的。那麼,還須要再定義一個CourseDetailSerializer,在get /courses/的時候,使用CourseSerializer,在get /courses/id/的時候,使用CourseDetailSerializer。
  那麼,問題來了,咱們怎麼獲取到是哪一個action方法?這個時候,viewset就出場了!.net

  • viewset的功能
      GenericViewSet繼承了GenericAPIView,依然有get_queryset,get_serialize_class相關屬性與方法,GenericViewSet重寫了as_view方法,能夠獲取到HTTP的請求方法。 解決剛剛的問題:
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方法註冊與綁定
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中的相關方法進行鏈接。
  在viewset中,還提供了兩個以及與mixins綁定好的ViewSet,固然,這兩個ViewSet徹底能夠本身實現:

class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    # 知足只有GET方法請求的情景
    pass
    
class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    # 知足全部請求都有的情景
    pass
複製代碼

  到這裏,ViewSet的強大功能就介紹完了,強烈建議在作drf的時候,使用ViewSet與mixins方法結合進行開發,爲我這種小白開發者提供了很強大完整的功能!

後言

  做者接下來還會對mixins等等進行總結,本人也爲初學者,若是有不對的地方,麻煩各位指出探討,感謝!

  CSDN地址:http://blog.csdn.net/l_vip/article/details/79131289
相關文章
相關標籤/搜索