所有视图的基类、Mixin类视图、通用视图类、视图子类、视图集、研究ModelViewSet、源码分析ViewSetMinxin

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。
APIView与View的不同之处

传入到视图方法中的是REST framework的对象,而不是Django的HttpResponse对象;

视图方法可以返回REST framework的Response对象,视图会为响应数据设置符合前端要求的格式;

任何APIView异常都会被捕获到,并且处理成适合的响应信息;

在进行dispatch分发前,会对请求进行身份认证、权限检查、流量控制。

支持定义的属性

authentication_classes列表或元祖,身份认证类

permissoin_classes列表或元祖,权限检查类

throttle_classes列表或元祖,流量控制类

在APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

GenericAPIView

rest_framework.generics.GenericAPIView

继承自APIView

主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持, 通常在使用时,可搭配一个或多个Mixin扩展类。

使用GenericAPIView类一般需要实现queryset属性或者重写get_queryset方法

支持定义的属性

列表视图与详情视图通用:

	queryset 指明表模型对象
	serializer_class视图使用的序列化器

列表视图使用:

	pagination_class分页控制类,默认内部分页用的静态字段
	filter_backends过滤控制后端,默认内部查询的静态字段
		filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

详情页视图使用:

	lookup_field查询单一数据库对象时使用的条件字段,默认为'pk',路由有名分组用的,这也就是有名分组,为什么只能填pk,因为这里写死了,如果我们想要有名分组的变量,叫XXX,需要在外部的视图配置一下,lookup_field = 'XXX'

	lookup_url_kwarg查询单一数据时URL中的参数关键字名称,默认与look_field相同

提供的方法

get_queryset(self)

一般内部使用,但是外部可以重写获得reuqest,返回视图使用的查询集,主要用来提供给Mixin扩展类使用,,是列表视图与详情视图获取数据的基础,默认返回`queryset`属性。,重写帮助视图拿到request,比如可以用于ListAPIView

返回视图使用的查询集,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写,例如:

def get_queryset(self):
	user = self.request.user
	return user.accounts.all()
get_serializer_class(self)

返回序列化器类,默认返回serializer_class,可以重写,例如:

def get_serializer_class(self):
	if self.request.user.is_staff:
		return FullAccountSerializer
	return BasicAccountSerializer
get_serializer(self,args, *kwargs)
外部使用,当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中,通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。

返回序列化器对象,被其他视图或扩展类使用,如果我们在视图中想要获取序列化器对象,可以直接调用此方法。

注意,在提供序列化器对象的时候,REST framework会向对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。

get_object(self)返回详情视图所需的模型类数据对象,默认使用lookup_field参数来过滤queryset。 在试图中可以调用该方法获取详情信息的模型类对象。

若详情访问的模型类对象不存在,会返回404。

该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。

Mixin类视图

使用基于类的视图的最大好处之一是它使我们能够轻松地组合可重用的行为
到目前为止,对于我们创建的任何基于模型操作的API视图,我们一直在使用的create 、 retrieve 、 update 、 delete操作将非常相似。这些常见行为在REST框架的mixin类中实现。

delete操作将非常相似。这些常见行为在REST框架的mixin类中实现。

mixin类提供用于提供基本视图行为的操作。

注意,mixin类提供了操作方法,而不是直接定义处理请求方法(例如.get()和.post())。

mixin类可以从导入rest_framework.mixins。

GenericAPIView 只是提供了数据,对应的访问功能是没有实现的,所以 DRF 还有五个提供方法的混入类,可以完成基本增删改查功能,我们也叫 Mixin 视图扩展类,通过 GenericAPIView 与视图扩展类的多继承,可以实现更加复杂的接口功能 GenericAPIView 提供数据,而视图扩展类提供操作

ListModelMixin:list方法,就是原来我们的get
CreateModelMixin:create方法,就是原来我们的post
RetrieveModelMixin:retrieve方法,就是我们原来写get
UpdateModelMixin:update方法,就是原来我们的put
DestroyModelMixin:destory方法,就是原来我们写的delete
class UserView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    # 获取所有的接口
    def get(self, request, *args, **kwargs):
        return self.list(*args, **kwargs)

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


class UserDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(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)

通用类视图 generics

通过使用mixin类,我们重写了视图,使其使用的代码比以前稍微少一些,但我们还可以更进一步。REST框架提供了一组已经混合在一起的通用视图,我们可以使用它们来进一步精简views.py模块。

子类视图(三级)

基于9个视图之类写接口
视图类:继承GenericAPIView+某个或某几个视图扩展类

from rest_framework.generics import ListAPIView,CreateAPIView,   RetrieveAPIView,DestroyAPIView,UpdateAPIView
from rest_framework.generics import ListCreateAPIView,     RetrieveUpdateDestroyAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView
# 正常来讲  Destroy+Update 应该有一个  ,作者没加
class UserView(ListCreateAPIView):
    # 配置两个 类属性
    queryset = User.objects.all()
    serializer_class = UserSerializer
class UserDetailView(RetrieveUpdateDestroyAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
*1) CreateAPIView*
提供 post 方法
继承自: GenericAPIView、CreateModelMixin

*2)ListAPIView*
提供 get 方法
继承自:GenericAPIView、ListModelMixin

*3)RetireveAPIView*
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin

*4)DestroyAPIView*
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin

*5)UpdateAPIView*
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin

*6)RetrieveUpdateAPIView*
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

*7)RetrieveUpdateDestoryAPIView*
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

*8) ListCreateAPIView*
提供 get、post方法
继承自:GenericAPIView、CreateAPIView、ListAPIView

*9) RetrieveDestroyAPIView*
提供 get、delete方法
继承自:GenericAPIView、RetireveAPIView、DestroyAPIView

视图集

导入模块 from rest_framework.viewsets import ModelViewSet
路由写法会改变,有映射关系的样子

path('user/', views.UserView.as_view({'get': 'list', 'post': 'create'})),
path('user/<int:pk>', views.UserDetailView.as_view({'get': 'list', 'post': 'create', 'delete': 'destroy'})),
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet

# ReadOnlyModelViewSet:只读,查询一个,查询所有
class UserViews(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
ViewSetMinxin:很厉害,就是它控制了路由的写法变了
ViewSet:APIView + ViewSetMinxin的组合
GenericViewSet:GenericAPIView + ViewSetMinxin的组合

谁在前谁在后是有关系的,它要去看谁在前就先继承谁,涉及到了查找顺序

研究ModelViewSet

ModelViewSet 继承了下面那一堆,在路由中配置as_view,虽然跟之前一样,但是执行的是ViewSetMinxin的as_view
	GenericViewSet = GenericAPIView + ViewSetMinxin
	mixins.CreateModelMixin,
	mixins.RetrieveModelMixin,
	mixins.UpdateModelMixin,
	mixins.DestroyModelMixin,
	mixins.ListModelMixin,

源码分析ViewSetMinxin

@classonlymethod
def as_view(cls, actions=None, **initkwargs):
    # 路由中as_view中必须传参数,必须传字典:{'get': 'list', 'post': 'create'}
    if not actions: 
        raise TypeError("The `actions` argument must be provided when "
                        "calling `.as_view()` on a ViewSet. For example "
                        "`.as_view({'get': 'list'})`")
	# 路由匹配成功,执行view(request),request是老的request
    def view(request, *args, **kwargs):
	    # actions={'get': 'list', 'post': 'create'}
        for method, action in actions.items():
            # method:get      action:list
            # self 是视图类的对象中通过反射,查找list,
            # handler视图类中的list方法
            handler = getattr(self, action)
            # 向视图类的对象中,反射 method:get,handler:list方法
            # self.get=list
            setattr(self, method, handler)
        return self.dispatch(request, *args, **kwargs)
    return csrf_exempt(view)


# 只要继承了ViewSetMixin,以后路由写法变量,都要协程:views.UserView.as_view({'get': 'list', 'post': 'create'}))
# 这样写好以后,对应的请求方式来了,就会执行配置的方法


# 扩展:
	-以后只要继承了ViewSetMixin,视图类中可以写任意名字的方法,不用非得写get,post,delete

image

posted @ 2022-10-02 17:26  小张不爱吃泡面  阅读(100)  评论(0编辑  收藏  举报