DRF框架学习(三)
1.视图
1.1作用
1.控制序列化器的执行(数据检验、数据保存、转换数据(序列化操作))
2.控制数据库的查询操作。
1.2类视图的两个基类
1.2.1APIView
是View类的子类,在view类的基础上添加了一些额外的功能。
功能:
1.视图中的request对象不再是Django中 HttpRequest
类的对象,而是由DRF框架封装成的 Request
类的对象。
2.响应时可以统一返回Response类的对象
3.异常处理:如果视图中抛出了未处理异常,DRF框架会自动对异常进行处理,并且会把处理之后的错误信息返回给客户端。例如 Http404
这个系统处理过的处理异常的方法,我们直接将它抛出,客户端就可以收到处理之后的错误信息,不会是404页面,而是错误信息,如“未找到“。
4.高级功能:
1)认证
2)权限
3)限流
Request类的对象:
1. request.data
里面保存解析之后的请求体数据,并且已经解析成了字典或类字典,相当于包含了Django原始request对象中的 request.body|request.POST|request.FILES
2. query_params
:保存解析之后的查询字符串数据,并且已经解析成了字典或类字典。 request.query_params
与Django标准的 request.GET
相同,只是更换了更正确的名称而已。
Response类的对象:
1.传入原始相应数据(比如一个字典),Response会自动根据客户端请求头中 Accept
将相应数据转换为对应的格式进行返回。默认是json格式。也可以指定返回的是网页,只需要将Accept设置为 text/html
即可。但是仅仅支持json和html两种。
为了方便设置状态码,REST framewrok在 rest_framework.status
模块中提供了常用状态码常量,我们直接使用即可。
status = status.HTTP_201_CREATED
上面的就可以指定201状态码了,我们直接写201的话,其他人容易看不懂,我们用常量让人易于理解。
1.2.2GenericAPIView
继承于APIView,是APIView的子类,在APIView的基础上添加操作序列化器和数据库查询的方法。封装的这些方法,我们可以直接使用。
补充知识点:
1.类视图对象有一个属性: self.kwargs
,它是一个字典,保存的是从url地址中提取的所有命名参数。它的作用:比如我们定义了一个视图,没有形参接收传递的参数,那么我们可以使用 self.kwargs
从url地址中提取我们需要的数据。
2. queryset
指定当前视图所使用的查询集;
serializer_class
指定当前视图所使用的序列化器类;
self.serializer_class
获取当前视图所使用的序列化器类;
serializer_cls=self.get_serializer_class()
获取当前视图所使用的序列化器类;
serializer_cls(*args,**kwargs)
创建一个序列化器类对象。
# 自定义一个GenericAPIView
classMyGenericAPIView(APIView):
queryset =None
serializer_class =None
lookup_field ='pk'
lookup_url_kwarg ='pk'
def get_serializer_class(self):
return self.serializer_class
def get_serializer(self,*args,**kwargs):
serializer_cls = self.get_serializer_class()
return serializer_cls(*args,**kwargs)
def get_queryset(self):
return self.queryset.all()
def get_object(self):
#从视图所使用的查询集中获取指定的对象,默认根据pk进行查询
# 获取当前视图所使用的查询集
query_set = self.get_queryset()# QuerySet
# filters = {'pk':self.kwargs['pk']}
filters ={self.lookup_field:self.kwargs[self.lookup_url_kwarg]}
try:
# obj = query_set.get(pk=self.kwargs['pk])
obj = query_set.get(**filters)
exceptException:
raiseHttp404
return obj
操作序列化器:
a)属性:
serializer_class
指定当前视图所使用的序列化器类。
b)方法:
get_serializer
创建一个视图所使用序列化器类的对象。
get_serializer_class
返回当前视图所使用的序列化器类。
数据库查询:
a)属性:
queryset
(指定视图所使用的查询集)
b)方法:
get_queryset
获取当前视图所使用的查询集。
get_object
从视图所使用的查询集中查询指定的对象,默认根据pk(查询)进行查询。
其他功能:
a)过滤
b)分页
补充知识点:
查询的时候我们想不根据主键pk查询,而是根据我们的需求查,那么可以根据修改 lookup_field
(值改为我们要查询的字段的名称)的值来解决需求。
lookup_url_kwarg
指定从查询集获取对象时,从url地址中提取的参数的名称。
注意:经常配合Minxin扩展类来使用。
1.3Mixin扩展类(重要)
classMyListModelMixin(object):
def list(self,request,*args,**kwargs):
"""获取一组数据的通用代码"""
.....
classMyCreateModelMixin(object):
def create(self,request,*args,**kwargs):
"""创建一条数据的通用代码"""
...
classMyRetrieveModelMixin(object):
def retrieve(self,request,*args,**kwargs):
"""获取指定的对象数据的通用过程"""
自己抽取代码实现扩展类的步骤:
1)先将通用的代码抽取出来。
2)创建一个扩展类,将抽取的代码进行封装。
3)在原视图函数中进行调用。
1.3.1扩展类5个详解
DRF框架提供了5个扩展类,封装了通用增删改查的流程。
1.3.1.1ListModelMixin
列表视图扩展类,提供 list(request,*args,**kwargs)
方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
源代码:
classListModelMixin(object):
"""
List a queryset.
"""
def list(self, request,*args,**kwargs):
# 过滤
queryset = self.filter_queryset(self.get_queryset())
# 分页
page = self.paginate_queryset(queryset)
if page isnotNone:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
# 序列化
serializer = self.get_serializer(queryset, many=True)
returnResponse(serializer.data)
举例:
from rest_framework.mixins importListModelMixin
classBookListView(ListModelMixin,GenericAPIView):
queryset =BookInfo.objects.all()
serializer_class =BookInfoSerializer
def get(self, request):
return self.list(request)
1.3.1.2CreateModelMixin
创建视图扩展类,提供 create(request,*args,**kwargs)
方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
源代码:
classCreateModelMixin(object):
"""
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)
returnResponse(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{}
1.3.1.3RetrieveModelMixin
详情视图扩展类,提供 retrieve(request,*args,**kwargs)
方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
源代码:
classRetrieveModelMixin(object):
"""
Retrieve a model instance.
"""
def retrieve(self, request,*args,**kwargs):
# 获取对象,会检查对象的权限
instance = self.get_object()
# 序列化
serializer = self.get_serializer(instance)
returnResponse(serializer.data)
举例:
classBookDetailView(RetrieveModelMixin,GenericAPIView):
queryset =BookInfo.objects.all()
serializer_class =BookInfoSerializer
def get(self, request, pk):
return self.retrieve(request)
1.3.1.4UpdateModelMixin
更新视图扩展类,提供 update(request,*args,**kwargs)
方法,可以快速实现更新一个存在的数据对象。
同时也提供 partial_update(request,*args,**kwargs)
方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。
源代码:
classUpdateModelMixin(object):
"""
Update a model instance.
"""
def update(self, request,*args,**kwargs):
partial = kwargs.pop('partial',False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance,'_prefetched_objects_cache',None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache ={}
returnResponse(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request,*args,**kwargs):
kwargs['partial']=True
return self.update(request,*args,**kwargs)
1.3.1.5DestroyModelMixin
删除视图扩展类,提供 destroy(request,*args,**kwargs)
方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
源代码:
classDestroyModelMixin(object):
"""
Destroy a model instance.
"""
def destroy(self, request,*args,**kwargs):
instance = self.get_object()
self.perform_destroy(instance)
returnResponse(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
1.3.2子类视图类
1.3.2.1CreateAPIView
提供 post 方法
继承自:GenericAPIView、CreateModelMixin
1.3.2.2ListAPIView
提供 get 方法
继承自:GenericAPIView、ListModelMixin
1.3.2.3RetrieveAPIView
提供get方法
继承自:GenericAPIView、RetrieveModelMixin
1.3.2.4DestoryAPIView
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin
1.3.2.5UpdateAPIView
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
1.3.2.6ListCreateAPIView
提供 get 和 post 方法
继承自:GenericAPIView、ListModelMixin、CreateModelMixin
1.3.2.7RetrieveUpdateAPIView
提供 get、put、patch方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin
1.3.2.8RetrieveDestroyAPIView
提供 get 和 delete 方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin
1.3.2.9RetrieveUpdateDestoryAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
公司中如果不知道该继承哪一个类,那么就继承APIView,完成了需求之后我们再进行代码的优化。时间长了之后,就知道该怎么写最简单的代码了。
2.视图集
2.1概念
将操作同一组资源的处理方法(API接口)同一个类中。(重要)
2.2注意点
1、视图集中的处理方法不再是以请求方式命名,而是以对应的操作名称(list、create、update、retrieve、destroy)
2、在进行url配置的时候,要指明请求地址的请求方式和视图集中处理函数之间的对应关系。
2.3视图集父类
ViewSet:
继承自ViewSetMixin和APIView
GenericViewSet:
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与 GenericAPIView
,所以还需要继承 GenericAPIView
。
GenericViewSet就帮助我们完成了这样的继承工作,继承自 GenericAPIView
与 ViewSetMixin
,在实现了调用as_view()时传入字典(如 {'get':'list'}
)的映射处理工作的同时,还提供了 GenericAPIView
提供的基础方法,可以直接搭配Mixin扩展类使用。
ModelViewSet:
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
ReadonlyModelViewSet:
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。
2.4视图集中添加额外的处理方法
1、直接在视图集中定义额外的处理方法即可
2、在进行url配置的时候指定请求地址请求方式和处理函数之间的对应的关系。