Django REST framework - View 視圖

APIView

APIView是rest framework中最常用也是最基本的一個視圖。APIView繼承自Django的View視圖,並對Django的原生request進行了一些封裝,主要封裝了驗證、權限、節流三部分。

先看一下APIView中驗證、權限、節流的流程是怎樣的
在這裏插入圖片描述
驗證
rest framework提供了一個驗證的基類與4個驗證類

class BaseAuthentication:
	    def authenticate(self, request):
        	raise NotImplementedError(".authenticate() must be overridden.")
        def authenticate_header(self, request):
        	pass


class BasicAuthentication(BaseAuthentication):


class SessionAuthentication(BaseAuthentication):


class TokenAuthentication(BaseAuthentication):


class RemoteUserAuthentication(BaseAuthentication):

如果想要自己實現驗證方法,可以通過繼承BaseAuthentication類並實現其中的兩個方法來實現。
然後看一下源碼中,rest frameworl是如何知道要使用自己寫的驗證方法還是系統自帶的驗證方法呢?
從上面的流程圖看,rest將驗證方法封裝到了Request這個類中。

    [rest_framework\views.py]
    def initialize_request(self, request, *args, **kwargs):
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

看一下self.get_authenticators(),會發現rest實際上是將self.authentication_classes中的類給實例化了。

    [rest_framework\views.py]
    def get_authenticators(self):
        return [auth() for auth in self.authentication_classes]

根據多繼承的繼承原理,首先會在自己的屬性中查找authentication_classes,如果沒有的話就去父類中查找,所以可以通過給authentication_classes賦值,來確定是使用自己寫的驗證方法還是系統的驗證方法。然後看一下APIView中對authentication_classes的定義

[rest_framework\views.py]
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

APIView中的authentication_classes是通過配置文件獲取的。所以這也是設置驗證方法的另外一種方法, 通過配置文件來配置需要使用哪些驗證方法。
定義自己的驗證方法

from rest_framework.authentication import BaseAuthentication


class MyAuthenticate(BaseAuthentication):
    def authenticate(self, request):

        return ( , ) or None or raise

    def authenticate_header(self, request):

        pass

在authenticate方法中有三種返回值,可以返回None表明這次驗證通過了,可以進行下面的驗證了,拋出一個異常,表明驗證失敗;返回一個元組。元組的信息爲(user_obj, auth_str)可以查看這部分源碼

[rest_framework\request.py]
def _authenticate(self):
    for authenticator in self.authenticators:
        try:
            user_auth_tuple = authenticator.authenticate(self)
        except exceptions.APIException:
            self._not_authenticated()
            raise

        if user_auth_tuple is not None:
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            return

    self._not_authenticated()

讓驗證失敗時,rest會返回匿名用戶,匿名用戶的信息可以通過配置文件配置。可以參考下面這部分源碼。

[rest_framework\request.py]
def _not_authenticated(self):
	self._authenticator = None
	if api_settings.UNAUTHENTICATED_USER:
    	self.user = api_settings.UNAUTHENTICATED_USER()
    else:
        self.user = None

    if api_settings.UNAUTHENTICATED_TOKEN:
    	self.auth = api_settings.UNAUTHENTICATED_TOKEN()
    else:
        self.auth = None

權限控制與節流跟驗證的流程大體相似,配置的方式基本相同,可以自己通過源碼查看一下,可以從下面這三個方法開始查看

self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)

GenericAPIView
GenericAPIView是對APIView進行的又一次封裝

class GenericAPIView(views.APIView):
    # 從數據庫中拿到的所有的樹
	def get_queryset(self):
	# 返回的一個對象
	def get_object(self):
	# 與序列化有關
	def get_serializer(self, *args, **kwargs):
	def get_serializer_class(self):
	def get_serializer_context(self):
	# 條件查詢
	def filter_queryset(self, queryset):
	# 與分頁有關
	@property
    def paginator(self):
    def paginate_queryset(self, queryset):
    def get_paginated_response(self, data):

GenericAPIView共實現了以上幾種方法,它幫我們做了很多事情。具體做了什麼事情可以自己查看這部分源碼。
viewsets中的視圖

class ViewSet(ViewSetMixin, views.APIView):
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):

在使用這四個視圖的時候,我們的路由就不能像前面那些視圖一樣,get請求調用get方法。
ViewSetMixin這個類重寫了as_view方法,改變了方法的調用。我們需要在寫路由的時候做出一些修改

	path('viewset', MyViewset.as_view({'get': ''list})),

我們可以自己配置請求方法對應的處理方法。我們來看一下as_view中的這部分源碼

@classonlymethod
def as_view(cls, actions=None, **initkwargs):
    ...
    def view(request, *args, **kwargs):
    	...
    	self.action_map = actions
    	for method, action in actions.items():
            handler = getattr(self, action)
            setattr(self, method, handler)
        ...

as_view根據我們傳入的actions字段來進行方法的調用。
既然有get了,那肯定還有其他的方法,比如post、uptade、delete等。
接下來看一下ModelViewSet,它繼承的類有很多,它所繼承的那些Minix類幫我們做的事情實際上就是實現了請求時所要調用的方法。
以mixins.CreateModelMixin爲例子

class CreateModelMixin:
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

從源碼中可以看出CreateModelMixin實現了create方法,所做的操作就是幫我們把數據添加到數據庫。同樣的其他的類也是事項的相應的方法。

class ListModelMixin:  # 獲取列表頁面
	def list(self, request, *args, **kwargs):

class RetrieveModelMixin:  # 獲取單條數據
    def retrieve(self, request, *args, **kwargs):

class UpdateModelMixin:  # 更新數據
    def update(self, request, *args, **kwargs):

class DestroyModelMixin:  # 刪除數據
    def destroy(self, request, *args, **kwargs):

如果要繼承ModelViewSet的話,還有一個問題,就是當要查詢單個數據、修改與刪除的時候需要傳入pk,而創建和查詢列表則不需要,這就要求我們在定義路由的時候要做出一些變化。

path('viewset'. MyViewset.as_view({'get': 'list'})),
path('viewset/<int: pk>'. MyViewset.as_view({'post': 'create'})),

將需要參數的url與不需要參數的url分開寫。
如果一個API繼承了所有的Mixin,即增刪改查都有。那麼可以使用route來更優雅的實現路由

from django.urls import path, include
from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'mypath', MyView)


urlpatterns = [
    path('test/', include(router.urls)),
]

使用這種方法,rest會自動添加上面兩種路由。
我們可以根據rest提供的這幾種Mixin實現不同的API接口,比如只繼承mixins.RetrieveModelMixin、mixins.ListModelMixin,和GenericViewSet的只讀APIReadOnlyModelViewSet

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章