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/'. 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

你可能感兴趣的:(django学习)