drf视图之两个视图基类、5个视图扩展类、9个视图子类以及视图集
两个视图基类
APIView
APIView是restframework提供的所有视图的基类,继承自django的view父类。
APIView与View的不同之处在于:
- 传入到视图方法中的是restframework的request对象,而不是django的Httprequest对象
- 视图方法可以返回restframework的response对象,视图会为响应数据设置render符合前端要求的格式
- 任何APIException异常都会被捕捉到,并且处理成合适的响应信息。
- 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
支持定义的类属性
- authentication_classes:列表或元组,身份认证类
- permission_classes:列表或元组,权限检查类
- throttle_classes:列表或元组,流量控制类
在APIView中仍以常规的类视图定义方法来实现get()、post()或者其他请求方法的方法。
GenericAPIView通用视图类
from rest_framework.generics import GenericAPIView
继承自APIView,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法。通常在使用时,可搭配一个活多个mixin扩展类
两个属性
-
queryset:指定要序列化的数据库查询的结果集
-
serializer_class:指名视图使用的序列化器
三个方法
get_queryset(self):
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写。例如:
def get_queryset(self):
user=self.request.user # 获取当前user表对象
return user.accounts.all() # 返回 user表扩表后的account表Queryset对象
get_serializer_class(self)或get_serializer(self,*args,**kwargs
)
-
get_serializer_class(self):当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化类名就可以让视图方法执行不同的序列化器对象了。返回序列化类,默认返回
serializer_class
,可以重写,例如:def get_serializer_class(self): if self.request.user.is_staff: return FullAccountSerializer return BasicAccountSerializer
-
get_serializer(self,*args,**kwargs)
返回序列化器对象,主要用来提供给mixin扩展类用,如果我们在视图中想要获取序列化器对象,也可以直接调用该方法
注意:该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view。这三个数据对象可以在定义序列化器时使用。
- request:当前视图的请求对象
- view:当前请求的类视图对象
- format:当前请求期望返回的数据格式
get_object(self)
返回详情视图所需的模类型数据对象,主要是用来提供给Mixin扩展类使用
在视图中调用该方法获取详情信息的模型类对象。若详情访问的模型类对象不存在,则会返回404
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
class BookAndDetail(Books,BookDetail):
queryset = Book.objects
serializer_class = BookSerializer
def put(self,request,pk):
res = self.get_object()
ser = self.get_serializer(instance=res, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功'}, status=201)
else:
return Response({'code':101,'msg':ser.errors})
补充了解:
filter_queryset: 跟过滤有关系
paginate_xxx: 跟分页有关
基于APIView写5个接口
基于GenericAPIView写5个接口
5个视图扩展类
作用:提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承响应的扩展类来复用代码,减少自己编写的代码量
这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法
ListModelMinxin
列表视图扩展类,提供list(request,*args,**kwargs)
方法快速实现列表视图,返回200状态码
该Mixin的list方法会对数据进行过滤和分页
源码
代码演示
from rest_framework.mixins import ListModelMixin
from app01 import models
class Books(ListModelMixin,GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = BookSerializer
def get(self,request):
return self.list(request)
CreateModelMixin
创建视图扩展类,提供create(request,*args,**kwargs)
方法快速实现创建资源的视图,成功返回201状态,如果序列化器对前端发送的数据验证失败,返回400错误。
源代码
RetrieveModelMinxin
详情视图扩展类,提供了retrieve(request,*args,**kwargs)
方法,可以快速实现返回一个存在的数据对象。如果存在,返回200,否则返回404.
源码
代码演示:
queryset = models.Book.objects.all()
serializer_class = BookSerializer
lookup_field = 'id'
def get(self,request,id):
instance=self.get_object()
return self.retrieve(request)
UpdateModelMixin
更新视图扩展类,提供update(reuqest,*args,**kwargs)
方法,可以快速实现更新一个存在的数据对象。
同时也提供了partial_update(reuqest,*args,**kwargs)
方法,可以实现局部更新,成功返回200,序列化器校验数据失败时,返回400错误。
源代码
DestoryModelMixin
删除视图扩展类,提供destory(reuqest,*args,**kwargs)
方法,可以快速实现删除一个存在的数据对象。成功返回204,不存在返回404.
源代码:
基于GenericAPIView+5个视图扩展类写接口
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
from app01 import models
class Books(ListModelMixin,CreateModelMixin,GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = BookSerializer
class BookDetail(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = BookSerializer
lookup_field = 'id' # 源码中默认为pk,可以指定修改
9个视图子类
from rest_framework.generics import ListAPIView,ListCreateAPIView,CreateAPIView
from rest_framework.generics import RetrieveAPIView,UpdateAPIView,DestroyAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView,RetrieveUpdateAPIView
基于9个视图子类写接口
class Books(ListCreateAPIView):
queryset = models.Book.objects.all()
serializer_class = BookSerializer
class BookDetail(RetrieveUpdateDestroyAPIView):
queryset = models.Book.objects.all()
serializer_class = BookSerializer
lookup_field = 'id'
视图集
视图集ViewSet
使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:
list() 提供一组数据
retrieve() 提供单个数据
create() 创建数据
update() 保存数据
destory() 删除数据
ViewSet视图集类不再实现get()、post()等方法,而是实现动作action如list()
、create()
等。视图集只能使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:
# 视图
class Book(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = BookSerializer
lookup_field = 'id'
def login(self,request):
return HttpResponse('登录')
# 一旦使用视图集中的类,就要这种写法:get请求对应的action是login方法,一旦发起get请求,就会执行对应的login方法
path('books/',views.Book.as_view({'get':'login','post':'create'})), path('books/<int:id>/',views.Book.as_view({'get':'retrieve','put':'update','delete':'destroy'}))
继承ModelViewSet编写5个接口
视图层
from rest_framework.viewsets import ModelViewSet
class Book(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = BookSerializer
lookup_field = 'id'
一旦使用视图集中的类,就要去路由修改写法
path('books/',views.Book.as_view({'get':'list','post':'create'})), path('books/<int:id>/',views.Book.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
常用视图集父类
ViewSet
继承自APIView
和ViewSetMixin
,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
ViewSet主要通过继承ViewSetMixin来实现调用as_view()
时传入字典(如{'get':'list'})的映射工作,在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
GenericViewSet
使用ViewSet并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法从而无序自己编写。但是Mixin扩展类依赖Generi'cAPIView,所以还需要继承GenericAPIView。
GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list
})的映射处理工作的同时,还提供了`GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用
class Book(GenericViewSet,ListCreateAPIView,RetrieveUpdateDestroyAPIView):
queryset =models.Book.objects
serializer_class = BookSerializer
lookup_field = 'id'
path('books/',views.Book.as_view({'get':'list','post':'create'})),
path('books/<int:id>/',views.Book.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
ModelViewSet
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
ReadOnlyModelViewSet
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin
源码分析ViewSetMixin
ViewSetMixin:是一个magic
一旦继承他之后:路由写法就变了,变成映射关系了,在视图类中可以写任意的方法名了
@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):
self = cls(**initkwargs)
# method:get action:list
# self 是视图类的对象中通过反射,查找list,
# handler视图类中的list方法
for method, action in actions.items():
handler = getattr(self, action)
# 向视图类的对象中,反射 method:get,handler:list方法
# self.get=list
setattr(self, method, handler)
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
return csrf_exempt(view)
'只要继承了ViewSetMixin,以后路由写法变了,都要写成:views.Book.as_view({'get':'list','post':'create'})'
这样写好以后,对应的请求方法来了,就会执行配置的方法
扩展:以后只要继承了ViewSetMixin,视图类中可以写任意名字的方法,不用非得写get,post,delete
总结
APIView
as_view,dispatch
GenericAPIView
继承了APIView
两个类属性
三个方法
5个视图扩展类
RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestoryModelMixin,ListModelMixin
每个类里面有一个方法
9个视图子类
5个视图扩展类+GenericAPIView的组合
视图集
ViewSetMixin:魔法,重写了as_view,只要继承他,路由写法就变了
ViewSet:ViewSetMixin+APIView
GenericViewSet:ViewSetMixin+GenericAPIView
ModelViewSet:5个视图扩展类+GenericViewSet
ReadOnlyModelViewSet:两个视图扩展类+GenericViewSet