Django REST framework API 指南(4):通用視圖

Django REST framework API 指南(1):請求
Django REST framework API 指南(2):響應
Django REST framework API 指南(3):視圖
Django REST framework API 指南(4):通用視圖
Django REST framework API 指南(5):視圖集
Django REST framework API 指南(6):路由
Django REST framework API 指南(7):解析python

官方原文連接數據庫

通用視圖

基於類的視圖的一個主要優勢是它們容許你編寫可重複使用的行爲。 REST framework 經過提供大量預構建視圖來提供經常使用模式,從而充分利用了這一點。django

REST framework 提供的通用視圖容許您快速構建緊密映射到數據庫模型的 API 視圖。api

若是通用視圖不符合需求,可使用常規的 APIView 類,或者利用 mixin 特性和基類組合出可重用的視圖。緩存

舉個栗子

一般,在使用通用視圖時,您須要繼承該視圖,並設置幾個類屬性。app

from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAdminUser,)
複製代碼

對於更復雜的狀況,您可能還想重寫視圖類中的各類方法。例如。ide

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAdminUser,)

    def list(self, request):
        # 注意使用`get_queryset()`而不是`self.queryset`
        queryset = self.get_queryset()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)
複製代碼

對於很是簡單的狀況,您可能想要使用 .as_view() 方法來傳遞類屬性。例如,您的 URLconf 可能包含相似於如下條目的內容:post

url(r'^/users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
複製代碼

直接在 URLconf 中設置相關屬性參數,這樣連視圖類都不用寫了。ui

API 參考

GenericAPIView

GenericAPIView 類繼承於 REST framework 的 APIView 類,爲標準列表和詳細視圖添加了常見的行爲。url

內置的每個具體的通用視圖都是經過將 GenericAPIView 類和一個或多個 minxin 類相互結合來構建的。

屬性

基本設置

如下屬性控制基本視圖行爲。

  • queryset - 用於今後視圖返回對象的查詢集。一般,您必須設置此屬性,或覆蓋 get_queryset()方法。若是你重寫了一個視圖方法,在視圖方法中,你應該調用 get_queryset() 而不是直接訪問這個屬性,這一點很重要!由於 REST 會在內部對 queryset 的結果進行緩存用於後續全部請求。
  • serializer_class - 用於驗證和反序列化輸入以及序列化輸出的序列化類。一般,您必須設置此屬性,或覆蓋 get_serializer_class() 方法。
  • lookup_field - 用於執行各個模型實例的對象查找的模型字段。默認爲 'pk'。請注意,使用 hyperlinked API 時,若是須要使用自定義值,則須要確保 API 視圖和序列化類設置了 lookup field。
  • lookup_url_kwarg - 用於對象查找的 URL 關鍵字參數。URL conf 應該包含與此值相對應的關鍵字參數。若是未設置,則默認使用與 lookup_field 相同的值。

關於後兩個參數,我這裏附上對象查詢的源碼你們就應該瞭解了。

省略部分代碼,方便理解

def get_object(self):
	# 先獲取數據集
    queryset = self.filter_queryset(self.get_queryset())
	# 拿到查詢參數的 key
    lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
	# 組裝成 {key:value} 的形式
    filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
    # 查詢
    obj = get_object_or_404(queryset, **filter_kwargs)
	# 最後返回
    return obj
複製代碼
分頁

與列表視圖一塊兒使用時,如下屬性用於控制分頁。

  • pagination_class - 對列表進行分頁時使用的分頁類。默認值與 DEFAULT_PAGINATION_CLASS 設置相同,即 rest_framework.pagination.PageNumberPagination。設置 pagination_class = None 將禁用此視圖的分頁。
過濾
  • filter_backends - 用於過濾查詢集的過濾器類的列表。默認值與 DEFAULT_FILTER_BACKENDS 設置的值相同。

方法

基本方法

get_queryset(self)

應該返回列表視圖的查詢集,並應該將其用做查看詳細視圖的基礎。默認返回由 queryset 屬性指定的查詢集。

應該始終使用此方法, 而不是直接訪問 self.queryset,由於 REST 會在內部對 self.queryset 的結果進行緩存用於後續全部請求。

能夠覆蓋以提供動態行爲,例如針對不一樣用戶的請求返回不一樣的數據。

舉個栗子:

def get_queryset(self):
    user = self.request.user
    return user.accounts.all()
複製代碼

get_object(self)

應該返回詳細視圖的對象實例。默認使用 lookup_field 參數來過濾基本查詢集。

能夠覆蓋以提供更復雜的行爲,例如基於多個 URL kwarg 的對象查找。

舉個栗子:

def get_object(self):
    queryset = self.get_queryset()
    filter = {}
    for field in self.multiple_lookup_fields:
        filter[field] = self.kwargs[field]

    obj = get_object_or_404(queryset, **filter)
    self.check_object_permissions(self.request, obj)
    return obj
複製代碼

請注意,若是您的 API 不包含任何對象級權限,您能夠選擇排除 self.check_object_permissions,並簡單地從 get_object_or_404 中查找返回對象。

filter_queryset(self, queryset)

給定一個查詢集,使用過濾器進行過濾,返回一個新的查詢集。

舉個栗子:

def filter_queryset(self, queryset):
    filter_backends = (CategoryFilter,)

    if 'geo_route' in self.request.query_params:
        filter_backends = (GeoRouteFilter, CategoryFilter)
    elif 'geo_point' in self.request.query_params:
        filter_backends = (GeoPointFilter, CategoryFilter)

    for backend in list(filter_backends):
        queryset = backend().filter_queryset(self.request, queryset, view=self)

    return queryset
複製代碼

get_serializer_class(self)

返回用於序列化的類。默認返回 serializer_class 屬性。

能夠被覆蓋以提供動態行爲,例如使用不一樣的序列化器進行讀寫操做,或爲不一樣類型的用戶提供不一樣的序列化器。

舉個栗子:

def get_serializer_class(self):
    if self.request.user.is_staff:
        return FullAccountSerializer
    return BasicAccountSerializer
複製代碼
保存和刪除鉤子(hook)

如下方法由 mixin 類提供,能夠很輕鬆的重寫對象的保存和刪除行爲。

  • perform_create(self, serializer) - 保存新對象實例時由 CreateModelMixin 調用。
  • perform_update(self, serializer) - 在保存現有對象實例時由 UpdateModelMixin 調用。
  • perform_destroy(self, instance) - 刪除對象實例時由 DestroyModelMixin 調用。

這些鉤子(hook)對設置請求中隱含的但不屬於請求數據的屬性特別有用。例如,您能夠根據請求用戶或基於 URL 關鍵字參數在對象上設置屬性。

def perform_create(self, serializer):
    serializer.save(user=self.request.user)
複製代碼

這些覆蓋點對於添加保存對象以前或以後發生的行爲(如發送確認電子郵件或記錄更新)也特別有用。

def perform_create(self, serializer):
    queryset = SignupRequest.objects.filter(user=self.request.user)
    if queryset.exists():
        raise ValidationError('You have already signed up')
    serializer.save(user=self.request.user)
複製代碼

注意:這些方法替代舊式版本2.x pre_savepost_savepre_deletepost_delete 方法,這些方法再也不可用。

其餘方法

一般不須要重寫如下方法,但若是使用 GenericAPIView 編寫自定義視圖,則可能須要調用它們。

  • get_serializer_context(self) - 返回包含應該提供給序列化的任何額外上下文的字典。默認包括 'request', 'view''format' 鍵。
  • get_serializer(self, instance=None, data=None, many=False, partial=False) - 返回一個序列化器實例。
  • get_paginated_response(self, data) - 返回分頁樣式的 Response 對象。
  • paginate_queryset(self, queryset) - 根據須要爲查詢集分頁,或者返回一個頁面對象;若是沒有爲該視圖配置分頁,則爲 None
  • filter_queryset(self, queryset) - 給定一個查詢集,使用過濾器進行過濾,返回一個新的查詢集。

Mixins

mixin 類用於提供基本視圖行爲的操做。請注意,mixin 類提供了操做方法,而不是直接定義處理方法,如 .get().post()。這容許更靈活的行爲組合。

mixin 類能夠從 rest_framework.mixins 中導入。

ListModelMixin

提供一個 .list(request, *args, **kwargs) 方法,實現了列出一個查詢集。

若是查詢集已填充,則返回 200 OK 響應,並將 queryset 的序列化表示形式做爲響應的主體。響應數據能夠設置分頁。

CreateModelMixin

提供 .create(request, *args, **kwargs) 方法,實現建立和保存新模型實例。

若是建立了一個對象,則會返回一個 201 Created 響應,並將該對象的序列化表示形式做爲響應的主體。若是表示包含名爲 url 的鍵,則響應的 Location header 將填充該值。

若是爲建立對象提供的請求數據無效,則將返回 400 Bad Request 響應,並將錯誤細節做爲響應的主體。

RetrieveModelMixin

提供 .retrieve(request, *args, **kwargs) 方法,該方法實如今響應中返回現有的模型實例。

若是能夠獲取對象,則返回 200 OK 響應,並將對象的序列化表示做爲響應的主體。不然,將返回一個 404 Not Found

UpdateModelMixin

提供 .update(request, *args, **kwargs) 方法,實現更新和保存現有模型實例。還提供了一個 .partial_update(request, *args, **kwargs) 方法,它與更新方法相似,只是更新的全部字段都是可選的。這容許支持 HTTP PATCH 請求。

若是成功更新對象,則返回 200 OK 響應,並將對象的序列化表示形式做爲響應的主體。

若是提供的用於更新對象的請求數據無效,則將返回 400 Bad Request 響應,並將錯誤細節做爲響應的主體。

DestroyModelMixin

提供一個 .destroy(request, *args, **kwargs) 方法,實現現有模型實例的刪除。

若是一個對象被刪除,則返回一個 204 No Content ,不然它將返回一個 404 Not Found

內置視圖類列表

如下類是具體的通用視圖。一般狀況下,你應該都是使用的它們,除非須要高度的自定義行爲。

這些視圖類能夠從 rest_framework.generics 中導入。

CreateAPIView

僅用於建立實例。

提供一個 post 請求的處理方法。

繼承自: GenericAPIView, CreateModelMixin

ListAPIView

僅用於讀取模型實例列表。

提供一個 get 請求的處理方法。

繼承自: GenericAPIView, ListModelMixin

RetrieveAPIView

僅用於查詢單個模型實例。

提供一個 get 請求的處理方法。

繼承自: GenericAPIView, RetrieveModelMixin

DestroyAPIView

僅用於刪除單個模型實例。

提供一個 delete 請求的處理方法。

繼承自: GenericAPIView, DestroyModelMixin

UpdateAPIView

僅用於更新單個模型實例。

提供 putpatch 請求的處理方法。

繼承自: GenericAPIView, UpdateModelMixin

ListCreateAPIView

既能夠獲取也能夠實例集合,也能夠建立實例列表

提供 getpost 請求的處理方法。

繼承自: GenericAPIView, ListModelMixinCreateModelMixin

RetrieveUpdateAPIView

既能夠查詢也能夠更新單個實例

提供 getputpatch 請求的處理方法。

繼承自: GenericAPIView, RetrieveModelMixinUpdateModelMixin

RetrieveDestroyAPIView

既能夠查詢也能夠刪除單個實例

提供 getdelete 請求的處理方法。

繼承自: GenericAPIView, RetrieveModelMixinDestroyModelMixin

RetrieveUpdateDestroyAPIView

同時支持查詢,更新,刪除

提供 getputpatchdelete 請求的處理方法。

繼承自: GenericAPIView, RetrieveModelMixinUpdateModelMixinDestroyModelMixin

自定義通用視圖類

一般你會想使用現有的通用視圖,而後稍微定製一下行爲。若是您發現本身在多個地方重複使用了一些自定義行爲,則可能須要將行爲重構爲普通類,而後根據須要將其應用於任何視圖或視圖集。

自定義 mixins

例如,若是您須要根據 URL conf 中的多個字段查找對象,則能夠建立一個 mixin 類。

舉個栗子:

class MultipleFieldLookupMixin(object):
    """ 將此 mixin 應用於任何視圖或視圖集以獲取多個字段過濾 基於`lookup_fields`屬性,而不是默認的單個字段過濾。 """
    def get_object(self):
        queryset = self.get_queryset()             # 獲取基本的查詢集
        queryset = self.filter_queryset(queryset)  # 使用過濾器
        filter = {}
        for field in self.lookup_fields:
            if self.kwargs[field]: # 忽略空字段
                filter[field] = self.kwargs[field]
        obj = get_object_or_404(queryset, **filter)  # 查找對象
        self.check_object_permissions(self.request, obj)
        return obj
複製代碼

隨後能夠在須要應用自定義行爲的任​​什麼時候候,將該 mixin 應用於視圖或視圖集。

class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    lookup_fields = ('account', 'username')
複製代碼

若是您須要使用自定義行爲,那麼使用自定義 mixins 是一個不錯的選擇。

自定義基類

若是您在多個視圖中使用 mixin,您能夠進一步建立本身的一組基本視圖,而後在整個項目中使用它們。例如:

class BaseRetrieveView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
    pass

class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin, generics.RetrieveUpdateDestroyAPIView):
    pass
複製代碼

若是自定義行爲始終須要在整個項目中的大量視圖中重複使用,那麼使用自定義基類是一個不錯的選擇。

相關文章
相關標籤/搜索