四、视图类

一、APIView详解

'''
# 1)安装drf:pip3 install djangorestframework
# 2)settings.py注册app:INSTALLED_APPS = [..., 'rest_framework']
# 3)基于cbv完成满足RSSTful规范的接口
'''

# 视图层
from rest_framework.views import APIView
from rest_framework.response import Response
user_list = [{'id': 1, 'name': 'Bob'}, {'id': 2, 'name': 'Tom'}]
class Users(APIView):
    def get(self, request, *args, **kwargs):
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': user_list
        })
    def post(self, request, *args, **kwargs):
        # request对formdata,urlencoded,json三个格式参数均能解析
        name = request.data.get('name')
        id = len(user_list) + 1
        user = {'id': id, 'name': name}
        user_list.append(user)
        return Response({
            'status': '0',
            'msg': 'ok',
            'results': user
        })

# 路由层
from app import views
urlpatterns = [
    url(r'^users/', views.Users.as_view()),
]

1、(APIView) as_view

'''
APIView是继承自View类

APIView内部重写了as_view方法,在该方法的内部,进行了以下几个步骤
	1. 调用父类View的as_view方法
	2. 存入当前类、参数到view中
	3. 调用装饰器csrf_exempt保障后续所有操作无需csrf校验(使用自己的校验方式)
'''
	@classmethod
    def as_view(cls, **initkwargs):
        # 调用父类View的as_view方法,并传入参数(先忽略此参数影响)
        view = super().as_view(**initkwargs)
        
        ''' 
       	python中一切皆对象,因此可以将view当作对象一般,存入属性或方法
        将当前类存入view.cls中
        将当前参数存入view.initkwargs中
        '''
        view.cls = cls
        view.initkwargs = initkwargs
		
        '''
        对于@csrf_exempt装饰器,我们可以直接添加在视图函数上面,作为不被csrf校验的依据,装饰器的本质原理,就是将被装饰函数作为参数传递给装饰器函数罢了
        因此,我们可以直接手动使用装饰器函数,传入需要装饰的函数作为装饰器函数的参数,从而达到@csrf_exempt一样的功能
        以下语法,就是对后续的所有执行动作,均不需要csrf校验
        '''
        return csrf_exempt(view)

2、(View) as_view

'''
上述操作,依然调用了父类View的as_view方法,我们来观察父类as_view方法内部实现
	1. 将当前类进行实例化
	2. 判断对象中是否存在get方法且不存在head方法,如果是,head则使用get方法
	3. 将request,args,kwargs使用对象属性存储
	4. 如果对象中不存在request,则抛出异常
	5. 调用当前对象中的dispatch方法,并传入request参数
'''
	'''
	classonlymethod本质就是继承于classmethod
	我们说python中一切皆对象,此刻classonlymethod就是继承自classmethod,并在其基础功能上增加了一些功能,原理依然是装饰此函数为类方法
	'''
	@classonlymethod
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):
            # 将当前类进行实例化
            self = cls(**initkwargs)
            
            # 判断对象中是否存在get方法且不存在head方法,如果是,head则使用get方法
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            
            '''
            setup是将request,args,kwargs使用对象属性存储
            	self.request = request
                self.args = args
                self.kwargs = kwargs
            '''
            self.setup(request, *args, **kwargs)
            
            # 如果对象中不存在request,则抛出异常
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
                
            # 调用当前对象中的dispatch方法,并传入request参数
            return self.dispatch(request, *args, **kwargs)
        
        # 存储当前类与initkwargs
        view.view_class = cls
        view.view_initkwargs = initkwargs

        update_wrapper(view, cls, updated=())

        update_wrapper(view, cls.dispatch, assigned=())
        
        # 返回view函数
        return view

3、(APIView) dispatch

'''
在观察了父类View的as_view方法后,我们发现其内部最终是调用dispatch方法(关键)

对于当前类,最近的dispatch方法,即是APIView中的dispatch方法,我们进行下一步研究:
	1. 加工原生request
	2. 增添三大认证模块
	3. 利用反射调用请求方法的对应方法
	4. 使用异常模块收集异常
	5. 利用渲染模块,渲染最终数据
'''
    def dispatch(self, request, *args, **kwargs):
        
        # 对当前接收参数使用对象属性存储
        self.args = args
        self.kwargs = kwargs
        
        # 将原生request,传入至initialize_request方法,进行加工后,返回加工后的request
        request = self.initialize_request(request, *args, **kwargs)

        # 此刻对象属性request存储的为加工后的reqeust
        self.request = request
        
        self.headers = self.default_response_headers  # deprecate?

        try:
            # 该方法内部包含三大认证模块
            self.initial(request, *args, **kwargs)
			
            
            '''
            反射:
            	1. 获取当前对象中的对应方法(get、post、put、patch、delete....)
           		2. 调用方法,并传入参数
           	
           	判断当前请求方式,是否存在于http_method_names属性中的方式
           	http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
           	
           	如果存在,则调用对象中的对应方法,否则使用默认方法http_method_not_allowed
            '''
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
                
                
			# 响应模块:执行对应方法,并传入 加工后的request参数
            response = handler(request, *args, **kwargs)
		
        
        except Exception as exc:
            # 异常模块:如果出现异常,则调用异常方法,返回对应的异常信息,而不是前端直接报错
            response = self.handle_exception(exc)
		
        # 渲染模块:将数据进行加工后,返还给前端精美的页面
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

A、(View) initialize_request

'''
我们进一步查看initialize_request方法内部原理:
	1. 返回封装后的request对象
	2. Request对象内包含原生request,以及其他功能
'''
	
        
            def initialize_request(self, request, *args, **kwargs):  

                '''
                parser_context返回一个列表
                	{
                	'view': self,							存储当前对象
                	'args': getattr(self, 'args', ()),		获取当前对象args属性值
                	'kwargs': getattr(self, 'kwargs', {})	获取当前对象kwargs属性值
                	}
                '''
                parser_context = self.get_parser_context(request)
				
                # 返回Request对象,传入初始化参数
                return Request(
                    request,									# 原生request
                    parsers=self.get_parsers(),					
                    '''
                    return [parser() for parser in self.parser_classes]
                    
                    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
                    '''
                    authenticators=self.get_authenticators(),
                    '''
                    return [auth() for auth in self.authentication_classes]
                    
                    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
                    '''
                    negotiator=self.get_content_negotiator(),
                    '''
                    if not getattr(self, '_negotiator', None):
            			self._negotiator = self.content_negotiation_class()
        			return self._negotiator
        			
        			content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
                    '''
                    
                    parser_context=parser_context				# 存储parser_context
                )
 

# Request对象
	self._request = request		# 原生request
	
	self.parser_context = parser_context
                	
    self.parser_context['request'] = self
    self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET

B、(APIView) initial

'''
initial内部存在三个,类似于钩子函数功能的组件:
	1. 认证组件
	2. 权限组件
	3. 频率组件
	
组件全部通过,才会继续正确执行,否则抛出403异常
'''
    def initial(self, request, *args, **kwargs):
        
        '''
        认证组件:校验用户 = 游客、合法用户、非法用户
            游客:代表校验通过,直接进入下一步校验(权限校验)
            合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
            非法用户:代表校验失败,抛出异常,返回403权限异常结果
        '''
        self.perform_authentication(request)
        
        '''
        权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
        	认证通过:可以进入下一步校验(频率认证)
        	认证失败:抛出异常,返回403权限异常结果
        '''
        self.check_permissions(request)
        
        '''
        频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
        	没有达到限次:正常访问接口
       		达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
        '''
        self.check_throttles(request)

二、GenericAPIView

'''
GenericAPIView是继承自APIView,封装后更加适合使用的一个视图类
'''
from rest_framework.generics import GenericAPIView

class xxx(GenericAPIView):
    '''
    首先,继承GenericAPIView必须写入以下两个属性
    	queryset:传入queryset对象
    	serializer_class:传入序列化器
    '''
    queryset = None
    # 例如:queryset = models.xxx.objects.all()
    self.get_queryset()
    '''
    def get_queryset(self):
    	queryset = self.queryset
        if isinstance(queryset, QuerySet):
            queryset = queryset.all()
        return queryset
        
        源码研究发现,queryset可以填写:(源码会判断加没加all,自动加all)
        	models.xxx.objects
        	models.xxx.objects.all()
       	使用get_queryset()就相当于使用queryset
    '''
    
    serializer_class = None
    # 例如:serializer_class = ZzwSerializer(定义的筛选器类)
    self.get_serializer(instance=None, data=empty, **kwargs, many=True, context={})
    '''
    def get_serializer(self, *args, **kwargs):
    	serializer_class = self.get_serializer_class()
        kwargs.setdefault('context', self.get_serializer_context())
        return serializer_class(*args, **kwargs)
    
   	def get_serializer_class(self):
        return self.serializer_class
        
    def get_serializer_context(self):
        return {
            'request': self.request,		
            'format': self.format_kwarg,
            'view': self
        }
    源码研究发现:
    	1. 使用serializer_class()就相当于使用serializer_class
    	2. 且serializer_class()会在原基础上增加三个参数,赋给context
    	3. 将get_serializer当作原来的序列化器,直接赋予序列化器的参数,即可使用
    '''
    
    self.get_object()
    '''
    def get_object(self):
    
    	queryset = self.filter_queryset(self.get_queryset())
    	lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
    	filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
        
        obj = get_object_or_404(queryset, **filter_kwargs)

        self.check_object_permissions(self.request, obj)

        return obj
    	
    1. 无需传入参数,直接获取当前pk的模型表数据对象
    2. 对于获取指定pk模型表数据、修改指定pk模型表数据、删除指定pk模型表数据,直接可以使用self.get_object()来代替
    '''
    

三、五个视图扩展类(增删改查)

1、ListModelMixin(获取所有)

from rest_framework.mixins import ListModelMixin


class ListModelMixin:

	# 标准获取模型表所有数据
    def list(self, request, *args, **kwargs):
    	
        queryset = self.filter_queryset(self.get_queryset())
		
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


2、CreateModelMixin(增加)

from rest_framework.mixins import CreateModelMixin    


class CreateModelMixin:

	# 直接一个完整的添加数据流程
    def create(self, request, *args, **kwargs):
    	# 1. 实例化序列化器,反序列化+校验用户传来的数据
        serializer = self.get_serializer(data=request.data)
        
        # 2. 判断数据是否符合校验规则
        serializer.is_valid(raise_exception=True)
        
        # 3. 调用perform_create方法,内部调用save()实现数据添加操作
        self.perform_create(serializer)
        
        # 4. 额外添加响应头
        headers = self.get_success_headers(serializer.data)
        
        # 5. 返回给前端数据
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}

3、UpdateModelMixin(修改)

from rest_framework.mixins import UpdateModelMixin


class UpdateModelMixin:
    
    # 标准修改操作
    def update(self, request, *args, **kwargs):
        # partial存在则删除,并返回被删除的value
        # 如果partial不存在,则设置value为False,并返回False
        partial = kwargs.pop('partial', False)
        
        # 1. 获取模型表指定pk的单条数据对象
        instance = self.get_object()
        
        # 2. 实例化序列化器,并传入 数据对象 和 用户传来的信息
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        
        # 3. 判断反序列化+校验是否通过,raise_exception指定,当未通过抛出异常ValidationError
        serializer.is_valid(raise_exception=True)
        
        # 4. 正常校验通过,则调用perform_update方法,内部执行修改操作
        self.perform_update(serializer)
·		
		# 5. 如果数据库记录对象,存在_prefetched_objects_cache字段,则设置为空字典
        if getattr(instance, '_prefetched_objects_cache', None):
            instance._prefetched_objects_cache = {}
		
        # 6. 返回修改后的数据
        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        # 设置partial为True
        kwargs['partial'] = True
        
        # 调用update方法
        return self.update(request, *args, **kwargs)

四、DestroyModelMixin(删除)

from rest_framework.mixins import DestroyModelMixin

class DestroyModelMixin:
	
    # 标准删除操作
    def destroy(self, request, *args, **kwargs):
        # 1. 获取模型表指定数据对象
        instance = self.get_object()
        
        # 2. 调用perform_destroy方法,内部直接删除模型表指定数据对象
        self.perform_destroy(instance)
        
        # 3. 返回空数据,状态码为204
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

五、RetrieveModelMixin(获取单个)

from rest_framework.mixins import RetrieveModelMixin

class RetrieveModelMixin:
    
    # 标准返回模型表中指定pk的单条记录
    def retrieve(self, request, *args, **kwargs):
        
        # 1. 获取模型表中指定pk的单条记录
        instance = self.get_object()
        
        # 2. 实例化序列化器,进行数据序列化
        serializer = self.get_serializer(instance)
        
        # 3. 将序列化后的数据传递给前端
        return Response(serializer.data)

四、封装好的九个接口

1、CreateAPIView(创建)

class CreateAPIView(mixins.CreateModelMixin, GenericAPIView):
	
    # 定义post方法,用于响应创建数据请求
    def post(self, request, *args, **kwargs):
        
        # 直接调用了CreateModelMixin类中的create方法,用于创建数据
        return self.create(request, *args, **kwargs)

2、ListAPIView(获取所有)

class ListAPIView(mixins.ListModelMixin, GenericAPIView):
    
    # 定义get方法,用于响应获取全部数据请求
    def get(self, request, *args, **kwargs):
        
        # 直接调用ListModelMixin中的list方法,获取全部数据
        return self.list(request, *args, **kwargs)

3、RetrieveAPIView(获取单个)

class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView):
    
    # 定义get方法,用于响应获取单个数据请求
    def get(self, request, *args, **kwargs):
        
        # 直接调用RetrieveModelMixin中的retrieve方法,获取指定数据
        return self.retrieve(request, *args, **kwargs)

4、DestroyAPIView(删除)

class DestroyAPIView(mixins.DestroyModelMixin,GenericAPIView):
    
    # 定义delete方法,用于响应删除指定数据请求
    def delete(self, request, *args, **kwargs):
        
        # 直接调用DestroyModelMixin中的destroy方法,删除指定数据 
        return self.destroy(request, *args, **kwargs)

5、UpdateAPIView(修改)

class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView):
    
    # 定义put方法,用于响应删除全局修改数据请求
    def put(self, request, *args, **kwargs):
        
        # 直接调用UpdateModelMixin中的update方法,删除指定数据 
        return self.update(request, *args, **kwargs)
	
	# 定义patch方法,用于响应局部修改指定数据请求
    def patch(self, request, *args, **kwargs):
        
        # 直接调用UpdateModelMixin中的partial_update方法
        # partial_update方法内部依然是带哦用update方法,从而删除指定数据 
        return self.partial_update(request, *args, **kwargs)

6、ListCreateAPIView(获取所有+增加)

class ListCreateAPIView(
    mixins.ListModelMixin,
    mixins.CreateModelMixin,
    GenericAPIView
):

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

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

7、RetrieveUpdateAPIView(获取单个+修改)

class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
                            mixins.UpdateModelMixin,
                            GenericAPIView):
   
    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 patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)

8、RetrieveDestroyAPIView(获取单个+删除)

class RetrieveDestroyAPIView(
    mixins.RetrieveModelMixin,
    mixins.DestroyModelMixin,
    GenericAPIView
):
    
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

9、RetrieveUpdateDestroyAPIView(获取单个+修改+删除)

class RetrieveUpdateDestroyAPIView(
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    mixins.DestroyModelMixin,
    GenericAPIView
):
 
    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 patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

五、ModelViewSet再封装

1、利用接口封装缺陷

from rest_framework.generics import RetrieveUpdateDestroyAPIView
from rest_framework.generics import ListCreateAPIView
from app01 import models

# 包含获取、删除、修改指定记录对象的操作
class Zzw1(RetrieveUpdateDestroyAPIView):
    queryset = 模型表对象
    # queryset = models.表名.objects
    serializer_class = 模型表对象
    # serializer_class = ZzwSerializer

# 包括获取所有、增加数据
class Zzw2(ListCreateAPIView):
    queryset = 模型表对象
    # queryset = models.表名.objects
    serializer_class = 模型表对象
    # serializer_class = ZzwSerializer

'''
根据drf封装好的九个接口,我们可以完成以上操作,使代码变得及其简单,但是:
	1. 能不能进一步封装?以上两个类、内部其实重复代码很多
	2. 需要解决重复get方法,才能实现!
'''

2、ModelViewSet源码

from rest_framework.viewsets import ModelViewSet

class ModelViewSet(
    mixins.CreateModelMixin,	# 增加
    mixins.RetrieveModelMixin,	# 获取单个
    mixins.UpdateModelMixin,	# 修改指定
    mixins.DestroyModelMixin,	# 删除指定
    mixins.ListModelMixin,		# 获取所有
    GenericViewSet				
):
    pass


class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    pass


class ViewSetMixin:
    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):
    	'''
    	重写了as_view,且新增了一个形参actions,此参数需要一个字典,且必填!
            actions = {
                'get': 'list',
                'post': 'create',
            }
    	actions用于设置方法与请求绑定,当post请求,则执行list方法,基于此原理,我们就可以实现如下操作
    	'''
        
        # 核心代码
        def view(request, *args, **kwargs):
  
        	for method, action in actions.items():
        		'''
                method:代表请求方式
                action:代表执行方法
             	'''
                
                '''
                使用反射,获取action代表的方法的内存地址
                例如:
                1. action假如是get方法
                	action ---> list()	
                2. 而方法和方法名实际上是变量名与内存地址的关系
                	action = 函数的内存地址
            	3. getattr如果对一个属性进行使用,那么他的返回结果是属性值(等号左边)
            	4. 反而思之,如果对一个方法使用,那么将获取该方法的内存地址
            		handler = action方法的内存地址
                '''
                handler = getattr(self, action)
                
                '''
                使用反射,创建一个新属性,并将函数内存地址赋值给method属性
                例如:
                1. method加入是get请求
                	method = handler
                	handler = action方法的内存地址
                	action ---> list()
                2. 最终将list内存地址赋值给method属性
                	method = list方法的内存地址
                3. 此刻如果是get请求,那么就会根据dispatch中的反射,自动执行get名称的方法/属性,而get名称的属性绑定了list方法的内存地址,所以就是执行list方法
                '''
                setattr(self, method, handler)

3、基于ViewSetMixin的视图类

# views.py
from rest_framework.viewsets import ViewSetMixin

# 一ViewSetMixin定要放在APIVIew前,才能实现请求--方法的映射绑定

class Book6View(ViewSetMixin,APIView): 
    def get_all_book(self,request):
        print("xxxx")
        book_list = Book.objects.all()
        book_ser = BookSerializer(book_list, many=True)
        return Response(book_ser.data)
    
# urls.py
    #继承ViewSetMixin的视图类,路由可以改写成这样,从而get请求执行get_all_book
    path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),

4、ModelViewSet实现五接口

# views.py
from rest_framework.viewsets import ModelViewSet

class xxx(ModelViewSet):
    queryset = 模型表对象
    # queryset = models.表名.objects
    serializer_class = 模型表对象
    # serializer_class = ZzwSerializer


# urls.py
path('xxx/', views.xxx.as_view(
    actions=
    {
        'get': 'list', 		# 获取所有
        'post': 'create'	# 创建数据
    }
))
# 2. 获取、删除、修改指定
re_path('xxx/(?P<pk>\d+)', views.xxx.as_view(
    actions=
    {
        'get': 'retrieve', 			# 获取指定
        'put': 'update',			# 修改指定(全局)	
        'patch': 'partial_update',	# 修改指定(局部)
        'delete': 'destroy',		# 删除指定
    }
))

六、视图类整理

# 两个基类:
    APIView(View)
    	from rest_framework.views import APIView
    GenericAPIView(APIView)
    	from rest_framework.generics import GenericAPIView,

# 五个视图扩展类
	from rest_framework.mixins import 
        ListModelMixin
        RetrieveModelMixin
        CreateModelMixin
        UpdateModelMixin
        DestoryModelMixin

# 九个子类接口
	from rest_framework.generics import
		ListAPIView(
            GenericAPIView, 
            mixins.ListModelMixin
		)
		RetrieveAPIView(
			mixins.RetrieveModelMixin,
            mixins.RetrieveModelMixin,
            mixins.RetrieveModelMixin,
			GenericAPIView,
			)
		CreateAPIView(
            mixins.CreateModelMixin, 
            GenericAPIView,
		)
		DestroyAPIView(
			mixins.DestoryModelMixin,
			GenericAPIView, 
		)
		UpdateAPIView(
			mixins.UpdateModelMixin
			GenericAPIView, 
		)
		ListCreateAPIView(
			mixins.ListModelMixin
			mixins.CreateModelMixin
			GenericAPIView, 
		)
		RetrieveDestroyAPIView(
			mixins.RetrieveModelMixin,
			mixins.DestoryModelMixin,
			GenericAPIView, 
		)
		RetrieveUpdateAPIView(
			mixins.RetrieveModelMixin,
			mixins.UpdateModelMixin,
			GenericAPIView, 
		)
		RetrieveUpdateDestroyAPIView(
			mixins.RetrieveModelMixin,
			mixins.UpdateModelMixin,
			mixins.DestoryModelMixin,
			GenericAPIView, 
		)

# 视图集
	from rest_framework.viewsets import
    	
        ViewSetMixin
    
		GenericViewSet(
			ViewSetMixin, 
            GenericAPIView
		)
		ReadOnlyModelViewSet(
			mixins.RetrieveModelMixin,
			mixins.ListModelMixin,
			GenericViewSet
		)
		ModelViewSet(
			mixins.CreateModelMixin,
			mixins.RetrieveModelMixin,
			mixins.UpdateModelMixin,
			mixins.DestroyModelMixin,
			mixins.ListModelMixin,
			GenericViewSet
		)
		
		ViewSet(
            ViewSetMixin,
            views.APIView
        )

 

posted @ 2021-07-04 19:38  zzwYYYYYY  阅读(67)  评论(0)    收藏  举报