django-rest-framework(概念篇)——apiview&viewset

一、django restframework介紹

Django生命周期:

前端發送請求-->Django的wsgi-->中間件-->路由系統-->視圖-->ORM數據庫操作-->模板-->返回數據給用戶

django rest framework生命周期

發送請求-->Django的wsgi-->中間件-->路由系統_執行CBV的as_view(),就是執行內部的dispath方法-->在執行dispath之前,有版本分析 和 渲染器-->在dispath內,對request封裝-->版本-->認證-->權限-->限流-->視圖-->如果視圖用到緩存( request.data or request.query_params )就用到了 解析器-->視圖處理數據,用到了序列化(對數據進行序列化或驗證) -->視圖返回數據可以用到分頁

http://www.cnblogs.com/Belter/p/7283945.html

二、django restframework使用

首先,我們看一下主要的幾種view以及他們之間的關系。


類繼承關系

這其中,還涉及了mixins,主要也分為5類:


mixins
  • 1.首先,我們使用django自帶的view,獲取一個課程的列表:
# 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)
    1. APIView
      接下來,我們用APIView來實現:
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做了很多東西,它定義了很多屬性與方法:


APIView
    1. 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再次封裝,實現了強大功能:

  • 加入queryset屬性,可以直接設置這個屬性,不必再將實例化的courses,再次傳給seriliazer,系統會自動檢測到。除此之外,可以重載get_queryset(),這樣就不必設置'queryset=*',這樣就變得更加靈活,可以進行完全的自定義。
  • 加入serializer_class屬性與實現get_serializer_class()方法。兩者的存在一個即可,通過這個,在返回時,不必去指定某個serilizer
  • 設置過濾器模板:filter_backends
  • 設置分頁模板:pagination_class

暫不清楚lookup_field的作用

  • 加入 lookup_field="pk",以及實現了get_object方法:這個用得場景不多,但十分重要。它們兩者的關系同上,要么設置屬性,要么重載方法。它們的功能在于獲取某一個實例時,指定傳進來的后綴是什么。

在generics除了GenericAPIView還包括了其他幾個View: CreateAPIView、ListAPIView、RetrieveAPIView、ListCreateAPIView···等等,其實他們都只是繼承了相應一個或多個mixins和GenericAPIView,這樣,有什么好處?我們看一下同樣一個例子的代碼:

class CourseListView(ListAPIView):
    """
    課程列表頁
    """
    queryset = Course.objects.all()
    serialize_class = CourseSerializer
    1. GenericViewSet
  • GenericAPIView的不足之處
    既然GenericAPIView以及它相關的View已經完成了許許多多的功能,那么還要ViewSet干嘛!
    首先,我們思考一個問題,同樣上面的例子,我們在功能上,要獲取課程的列表,也要獲取某個課程的具體信息。那么怎么實現,按照GenericAPIView,我們可以這樣實現:
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就出場了!

  • 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)),]
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容