1. 程式人生 > >[Django] Django REST Framework(三):APIView、GenericAPIView、Mixins總結

[Django] Django REST Framework(三):APIView、GenericAPIView、Mixins總結

概述

APIView是DRF的檢視層中最基本的類,它相當於Django中的View類,其他檢視類都是通過繼承APIView實現的。

GenericAPIView繼承於APIView,在其父類的基礎上為列表檢視和詳情檢視添加了常用的行為。

Mixins提供了一些基本檢視行為的操作方法,如提供的list()方法將返回查詢集,等等。因為Python多繼承的特性,因此,在定義檢視時可以將GenericAPIViewMixins進行靈活的組合。而DRF中就提供了許多這樣的類可以供我們完成所有所需的View。

1.APIView

在DRF中提供了APIView,繼承於Django的View

,作為最基本的類檢視,處理使用者的請求並返回響應。和View相比,APIView有如下特點:

  • 1.傳遞給處理方法的請求是DRF的Request例項,而不是Django的HttpRequest例項;
  • 2.響應並返回的是DRF的Response物件,而不是Django的HttpResponse物件;
  • 3.任何APIException異常都會被捕獲並調製到適當的響應中;
  • 4.會對接收的請求進行身份認證和許可權的檢查。

和使用View類似,使用APIView時,接收的請求會被dispatch到對應的方法中,如get()post()……此外,還可以設定許多屬性來控制API各個方面的策略。

使用APIView

時需要匯入其所在模組:

from rest_framework.views import APIView

基本的使用APIView方式舉例如下:

class SnippetList(APIView):

    # 處理GET請求
    def get(self, request, format=None):

        snippet = Snippet.objects.all()
        serializer = SnippetSerializer(snippet, many=True)
        return Response(serializer.data)

    # 處理POST請求
def post(self, request, format=None): serializer = SnippetSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)

1.1.常用屬性

.authentication_classes

該屬性用於指定當前View endpoint的身份驗證類,如:

from rest_framework.authentication import TokenAuthentication


class TestView(APIView):

    authentication_classes = (TokenAuthentication,)
    # ......

使用authentication_classes設定的身份驗證類將僅僅對該View驗證有效,如果需要對整個專案有效,則需要在settings.py配置檔案中進行設定:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        # ......
        'rest_framework.authentication.authentication.TokenAuthentication',
    )
}

DEFAULT_AUTHENTICATION_CLASSES也是身份驗證類列表的預設值。

.permission_classes

該屬性用於指定當前View endpoint的許可權類列表,如:

from rest_framework import permissions
class SnippetList(APIView):
    # ...
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,permissions.IsAuthenticated,permissions.IsAdminUser)
    # ...

如果不指定該屬性,則預設使用settings.DEFAULT_PERMISSION_CLASSES中指定的許可權列表。

APIView是DRF中所有View的基類,也是DRF中檢視層的基礎,但APIView並不是重點,重點是下面的GenericAPIViewMixins以及兩個混合組成的許多類。

2.GenericAPIView

GenericAPIView繼承於APIView,為常用的列表檢視和詳細檢視提供了一些操作屬性方法。

使用GenericAPIView時需要匯入對應模組:

from rest_framework import generics

其基本使用方式如下:

from .serializers import SnippetSerializer
from .models import Snippet
# Create your views here.


class Show(generics.GenericAPIView):

    # 指定序列化類
    serializer_class = SnippetSerializer
    # 指定QuerySet物件
    queryset = Snippet.objects.all()

    def get(self, request):
        return Response("hello world...")

    def post(self, request):
        return Response(request.data)

2.1.常用屬性和方法

.queryset

指定要顯示的Model物件的QuerySet物件(查詢集),用於列表檢視中。在GenericAPIView中必須指定該屬性或者重寫get_queryset()方法。

.serializer_class

指定要顯示的Model物件的Serializer物件,在GenericAPIView中必須指定該屬性或者重寫get_serializer()方法。

.lookup_field

指定用於查詢單個Model例項的Model欄位,預設為pk.

.lookup_url_kwarg

指定用於Model查詢的url關鍵字引數,如果未設定,則預設使用與lookup_field的值。

.pagination_class

指定列表檢視中用於分頁的分頁類列表,可以對響應列表進行分頁。預設使用配置檔案中DEFAULT_PAGINATION_CLASS的值。

.filter_backends

指定用於過濾查詢集的過濾器後端類列表。 預設使用為DEFAULT_FILTER_BACKENDS設定的值。

.get_queryset(self)

返回用於列表檢視的查詢集,預設返回queryset屬性指定的查詢集。

NOTE:
應始終使用此方法而不是直接訪問self.queryset,因為self.queryset僅被評估一次,然後將結果進行快取用於所有後續請求。

.get_object(self)

返回用於詳情檢視中的Model物件例項,預設使用lookup_field欄位過濾QuerySet中的資料。

.get_serializer()

返回用於Model序列化的Serializer類,預設返回serializer_class屬性的值,該方法可以用來動態指定一個序列化類。

3.Mixin

通常GenericAPIView不會單獨使用,因為它相比APIView,僅僅提供了一些公共的用於列表檢視和詳情檢視的屬性和方法,GenericAPIView需要和Mixins組合使用。

Mixin類中提供了許多用於對檢視進行操作的方法,這些操作方法無須我們自己實現就可以使用了。比如,ListModelMixin提供了一個list()方法用於將Model的查詢集響應給客戶端,因此可以用於列表檢視的get()中:

class show(generics.GenericAPIView,mixins.ListModelMixin):

    serializer_class = SnippetSerializer
    queryset = Snippet.objects.all()

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

相比使用APIView,簡化了非常多的操作。

使用Mixins需要匯入其所在模組:

from rest_framework import mixins

下面對常用Mixins類及其功能進行下總結。

3.1.ListModelMixin

該類提供了一個.list(request, *args, **kwargs)方法,用於列出查詢集QuerySet。如果queryset被填充,則響應碼為200,並將查詢集序列化作為響應體響應給客戶端。

3.2.CreateModelMixin

該類提供一個.create(request, *args, **kwargs)方法,用於建立並儲存一個新的Model例項,因此用在POST請求中,和post()方法組合使用。如果Model例項建立成功,則響應碼為201 Created ,並將物件序列化後作為響應體響應給客戶端;如果Model例項建立失敗,則響應碼為401(Bad Request),並將錯誤資訊作為響應體。

3.3.RetrieveModelMixin

該類提供一個retrieve(request, *args, **kwargs)方法,用於檢索並返回一個現有的Model例項。如果能夠檢索到物件,則返回200 OK響應,並將物件序列化後作為響應體輸出,否則返回404 Not Found響應。

3.4.UpdateModelMixin

該類提供一個update(request, *args, **kwargs)方法,用於更新並儲存現有的Model物件。因此用在PUT請求中,和put()方法組合使用。如果更新成功,則返回200 OK響應,並將物件序列化後作為響應體輸出,否則返回400 Bad Request響應。

3.5.DestroyModelMixin

該類提供一個.destroy(request, *args, **kwargs)方法,用於刪除一個已存在的Model例項。如果刪除成功返回204 No Content響應,否則返回404 Not Found響應。

以上方法無須我們再進行實現,直接使用即可,如以下示例:

class SnippetDetail(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    mixins.CreateModelMixin,
                    generics.GenericAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    # get,put,delete方法是GenericAPIView中提供
    # retrieve,update,destory方法由Mixin類檢視提供
    # 二者可以靈活的結合
    def get(self, request, *args, **kwargs):
        return self.list(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)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

4.常用具體通用檢視

在DRF中,除了提供Mixin類之外,還提供了GenericAPIViewMixins的組合View類,這些類稱為具體通用檢視。因此我們不需要只需要具體通用檢視就可以實現我們所需的功能,如:

from rest_framework import generics

class show(generics.ListCreateAPIView):

    serializer_class = SnippetSerializer
    queryset = Snippet.objects.all()

在這個示例中,ListCreateAPIView繼承自GenericAPIView, ListModelMixin, CreateModelMixin這三個類,並且內部已經將對應請求方法和操作方法進行了實現,我們只需要指定一些屬性即可,無須再寫get()post()請求方法邏輯。

下面是一些常用的具體通用檢視。
使用這些類時需要匯入所在模組:

from rest_framework import generics

4.1.ListCreateAPIView

父類:GenericAPIView, ListModelMixin,CreateModelMixin
特點:已提供了get()put()方法處理。

4.2.RetrieveUpdateDestroyAPIView

父類:GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
特點:已提供了get()put()patch()destory()方法處理。

其他具體通用檢視,還請參考官方文件.

5.重構View示例

現在,利用以上View內容以及Django中的函式檢視等內容,從函式檢視開始,一步步對檢視進行重構,看看其簡化的過程。

Step1.最初的函式檢視
# 列表檢視
@api_view(['GET', 'POST'])
def student_list(request):

    # 處理GET請求
    if request.method == 'GET':

        student = Student.objects.all()
        serializers = StudentSerializer(student, many=True)
        return Response(serializers.data)

    # 處理POST請求
    if request.method == 'POST':
        serializer = StudentSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(status=status.HTTP_400_BAD_REQUEST)


# 詳情檢視
@api_view(['GET', 'POST'])
def student_detail(request, pk):
    if request.method == 'GET':

        student = Student.objects.get(pk=pk)
        serializer = StudentSerializer(student)
        return Response(serializer.data)

    if request.method == 'POST':

        serializer = StudentSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(status=status.HTTP_400_BAD_REQUEST)
Step2.將函式檢視用APIView替換

現在通過APIView進行重構,可以定義請求對應的get()方法和post()方法,重構後如下所示:

from rest_framework.response import Response
from hello.models import Student
from hello.serializers import StudentSerializer
from rest_framework import status
from rest_framework import views

# 列表檢視
class StudentList(views.APIView):

    # GET請求
    def get(self,request):
        student = Student.objects.all()
        serializer = StudentSerializer(student,many=True)
        return Response(serializer.data)

    # POST請求
    def post(self, request):

        serializer = StudentSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)


# 詳情檢視
class StudentDetail(views.APIView):

    def get(self, request, pk):
        student = Student.objects.get(pk=pk)
        serializer = StudentSerializer(student)
        return Response(serializer.data)

    def post(self, request):
        serializer = StudentSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)
Step3.GenericAPIView+Mixins替換APIView

GenericAPIView相比APIView,提供了部分屬性;Mixins提供了許多用於對檢視進行操作的方法:

from rest_framework.response import Response
from hello.models import Student
from hello.serializers import StudentSerializer
from rest_framework import status
from rest_framework import generics
from rest_framework import mixins
from django.http import Http404


class StudentList(generics.GenericAPIView, minxins.ListModelMixin, mixins.CreateModelMixin):

    # 指定序列化類
    serializer_class = StudentSerializer
    # 執行Model物件查詢集
    queryset = Student.objects.all()
    # 如果不對query_set的值進行修改,沒有必要重寫該方法
    def get_queryset(self):
        return Student.objects.all()

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)

# 詳情檢視
class StudentDetail(generics.GenericAPIView,
                    mixins.RetrieveModelMixin):

    def get(self, request, *args, **kwargs):
        return self.retrieve(self, request, *args, **kwargs)
Step4.使用具體通用檢視替換GenericAPIView+Mixins
from hello.models import Student
from hello.serializers import StudentSerializer
from rest_framework import generics

# 列表檢視
class StudentList(generics.ListCreateAPIView):

    serializer_class = StudentSerializer
    queryset = Student.objects.all()


# 詳情檢視
class StudentDetail(generics.RetrieveUpdateDestroyAPIView):

    queryset = Student.objects.all()
    serializer_class = StudentSerializer

通過具體通用檢視,兩行程式碼就搞定。

總結

DRF中提供了這麼多View,但無非就是從views.View這個基類,通過繼承、mixin實現而已。因此,在學習這些類時,不必死記硬背,而是通過其繼承結構、實現原始碼,瞭解明白它的作用和使用方式,以及和mixin的混合使用,這樣才可以更好的使用DRF中的各種View。