drf请求、响应与视图
一、请求
1 定义
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
由于这个Request类内部重写了__getattr__
方法,所以原来的request类的方法在新的request也可以点出来使用
2 常用属性
1).data
request.data
返回解析之后的请求体数据。类似于Django中标准的request.POST
和 request.FILES
属性,但提供如下特性:
- 包含了解析之后的文件和非文件数据
- 包含了对POST、PUT、PATCH请求方式解析后的数据
- 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
2).query_params
request.query_params
与Django标准的request.GET
相同,只是更换了更正确的名称而已。
总结:在drf中基本上使用的数据都是request.data,因为django原生的request不会解析json数据
二、响应
1 Response
rest_framework.response.Response
drf提供了一个响应类Response,该类在构造响应对象的时候,响应会被转化(render)成符合前端需求的类型,这一步在drf重写的dispatch源码中有。
但是我们可以发现,如果我们是浏览器发起请求得到的是一个页面,如果是postman发起请求,得到的直接就是json数据,这是内部帮我们判断了一下。
drf也提供了修改默认值的方法,让我们可以在前端也直接接受json格式的数据
# 在settings.py中添加(这是默认的,不加也是这样)
# 默认原来的出处在drf的settings里
# 当发起响应的时候,会先在我们项目的settings内找,找不到再去默认的里找
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
# 注释掉下面任意一条就只能返回另一条了
'rest_framework.renderers.JSONRenderer', # json渲染器
'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器
)
}
2 构造方法
Response(data, status=None, template_name=None, headers=None, content_type=None)
参数说明:
data
: 为响应准备的序列化处理后的数据,通常放一个字典;status
: 状态码,默认200;template_name
: 模板名称,如果使用HTMLRenderer
时需指明,通常不用;headers
: 用于存放响应头信息的字典,放一个字典;content_type
: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
3 状态码
为了方便设置状态码,REST framewrok在rest_framework.status
模块中提供了常用状态码常量。
1)信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
2)成功 - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
3)重定向 - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
4)客户端错误 - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
5)服务器错误 - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
三、视图
1 基类视图 APIView
apiview是drf中所有视图类的基类,它继承自djangoview
在前几篇中有对应的源码分析,apiview和view的区别:
- 传入到视图类中的request是drf新封装的,是在原来request上扩展的,所以原来的属性方法也能直接使用
- 返回的response,会在apiview内部渲染成符合前端要求的格式(json或者html)
- 任何APIException都会被捕获,并且处理成合适的响应信息
- 在执行apiview内的dispatch方法,会对请求身份认证,权限检查,流量控制
支持定义的类属性
- authentication_classes 列表或元祖,身份认证类
- permissoin_classes 列表或元祖,权限检查类
- throttle_classes 列表或元祖,流量控制类
APIView实现5个常用的api接口
class StudentAPI(APIView):
def get(self,request,pk):
obj = models.Student.objects.filter(pk = pk).first()
ser_boj = ser.StudentSerializer(obj)
return JsonResponse(ser_boj.data)
def put(self,request,pk):
back_dic = {'code':200,'msg':'成功'}
obj = models.Student.objects.filter(pk = pk).first()
ser_obj = ser.StudentSerializer(obj,request.data)
if ser_obj.is_valid():
ser_obj.save()
back_dic['data'] = ser_obj.data
else:
back_dic['code'] = 100
back_dic['msg'] = '出错'
back_dic['error_msg'] = ser_obj.errors
return JsonResponse(back_dic)
def delete(self,request,pk):
obj = models.Student.objects.filter(pk=pk).first()
if obj:
obj.delete()
back_dic = {'code': 200, 'msg': '成功','data':{}}
else:
back_dic = {'code': 100, 'msg': '失败','error_msg':'用户不存在'}
return Response(back_dic)
class StudentsAPI(APIView):
def post(self,request):
# print(request.data)
back_dic = {'code': 200, 'msg': '成功'}
obj = ser.StudentSerializer(data = request.data)
if obj.is_valid():
obj.save()
back_dic['data'] = obj.data
else:
back_dic['code'] = 100
back_dic['msg'] = '错误'
back_dic['error_msg'] = obj.errors
return (back_dic)
def get(self,request):
obj = models.Student.objects.all()
obj_ser = ser.StudentSerializer(obj,many=True)
back_dic = {'code':200,'msg':'正确','data':obj_ser.data}
return Response(back_dic,status=201)
2 通用视图类 GenericAPIView
继承自APIView,主要增加了统一视图类的查询集和序列化器,作为给下面的Mixin扩展类的执行提供方法支持,通常在使用的时候回搭配Mixin扩展类使用
内部提供的关于序列化器的属性和方法:
属性:serializer_class指明视图使用的序列化器
这个属性对应的方法:
get_serializer_class(self)
这个方法返回的是是序列化器类,如果我们这个视图类中要根据不同情况使用不同的序列化器类的时候即可重写这个方法
def get_serializer_class(self):
if self.request.user.is_staff:
return FullAccountSerializer
return BasicAccountSerializer
这个方法如果不重写,默认会返回我们在属性里定义的serializer_class指定的序列化器类
get_serializer(self, args, *kwargs)
这个方法返回的是序列化器对象,主要用来提供给后面介绍的Mixin扩展类使用,如果我们想在视图类中获取序列化器对象,也可以直接使用这个方法
内部传参和调用序列化器类一样
stu_ser = self.get_serializer(instance = self.get_queryset(),many = True)
# data 接受修改的数据
注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。
- request 当前视图的请求对象
- view 当前请求的类视图对象
- format 当前请求期望返回的数据格式
属性:queryset:指明使用的数据查询集
方法:get_queryset(self)
返回视图使用的查询集,通常提供给Mixin扩展类使用
若返回的模型对象不存在,返回404
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
举例:
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
class BookDetailView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer def get(self, request, pk):
book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象
serializer = self.get_serializer(book)
return Response(serializer.data)
其他可以设置的属性
pagination_class 指明分页控制类
filter_backends 指明过滤控制后端
基于GenericAPIView写5个api
# get全部,post单个
class StudentsGenericAPI(GenericAPIView):
queryset = models.Student.objects.all()
serializer_class = ser.StudentModelSerializer
def get(self,request):
stu_ser = self.get_serializer(instance = self.get_queryset(),many = True)
return Response(stu_ser.data)
def post(self,request):
print(request.data)
stu_ser = self.get_serializer(data=request.data)
if stu_ser.is_valid():
stu_query = stu_ser.save()
stu_ser = self.get_serializer(stu_query)
return Response(stu_ser.data)
return Response(stu_ser.errors)
# get单个,put单个,del单个
class StudentGenericAPI(GenericAPIView):
queryset = models.Student.objects
serializer_class = ser.StudentModelSerializer
def get(self,request,pk):
stu_ser = self.get_serializer(self.get_queryset().filter(pk=pk).first())
return Response(stu_ser.data)
def put(self,request,pk):
stu_ser = self.get_serializer(self.get_queryset().filter(pk=pk).first(),data=request.data)
if stu_ser.is_valid():
stu_ser.save()
return Response(stu_ser.data)
return Response(stu_ser.errors)
def delete(self,request,pk):
self.get_queryset().filter(pk=pk).first().delete()
return Response({'msg':'删除成功'})
序列化器类:
from rest_framework import serializers
from students.models import Student
class StudentModelSerializer(serializers.ModelSerializer):
class Meta:
model= Student
fields = "__all__"
class StudentModel2Serializer(serializers.ModelSerializer):
class Meta:
model= Student
fields = ("name","class_null")
3 扩展类Mixin
# 基于视图扩展类写的api
# 相比于只用Generic,把5个api方法都在对应的视图扩展类中写了,只要继承调用即可
# 对应关系如下
# list:get全部,create:post,update:put,destroy:delete,retrieve:get单个
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
class Students2API(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = models.Student.objects
serializer_class = ser.StudentModelSerializer
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class Student2API(GenericAPIView,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin):
queryset = models.Student.objects
serializer_class = ser.StudentModelSerializer
def put(self,request,pk):
return self.update(request,pk)
def get(self,request,pk):
return self.retrieve(request,pk)
def delete(self,request,pk):
return self.destroy(request,pk)
4 GenericAPIView的视图子类
#GenericAPIView的视图子类 9个
from rest_framework.generics import CreateAPIView,ListAPIView,UpdateAPIView,RetrieveAPIView,DestroyAPIView,ListCreateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView,RetrieveUpdateAPIView
# 视图子类在5个扩展类的基础上,把我们函数的方法写到内部去了
# 所以下面我们只要继承这些视图类,然后定义查询集和序列化器就能根据请求的不同自动调用对应的视图函数
# 对应关系如下
# 单个的对应关系,list:get全部,create:post,update:put,destroy:delete,retrieve:get单个
# 多个的对应关系,ListCreate:get全部+post,RetrieveUpdateDestroy:get单个+put+delete
# 多个的对应关系,RetrieveDestroy:get单个+delete,RetrieveUpdate:get单个+put
class Students3API(ListCreateAPIView):
queryset = models.Student.objects
serializer_class = ser.StudentModelSerializer
class Student3API(RetrieveUpdateDestroyAPIView):
queryset = models.Student.objects
serializer_class = ser.StudentModelSerializer
5 视图集
1) ViewSet
继承自APIView
与ViewSetMixin
,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{'get':'list'})的映射处理工作。
在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
总结:扩展性高,自动化程度低
2)GenericViewSet
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView
,所以还需要继承GenericAPIView
。
GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView
与ViewSetMixin
,在实现了调用as_view()时传入字典(如{'get':'list'}
)的映射处理工作的同时,还提供了GenericAPIView
提供的基础方法,可以直接搭配Mixin扩展类使用。
举例:
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
url的定义
urlpatterns = [
path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})),
re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})),
]
3)ModelViewSet
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
# 使用ModelViewSet写5个api,url需要修改
# ModelViewSet继承了5中扩展视图类,所以只要配置好就可以使用5个对应的api方法
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSetMixin
class Students4API(ModelViewSet):
queryset = models.Student.objects
serializer_class = ser.StudentModelSerializer
# urls
url(r'^student4/$',views.Students4API.as_view(actions={
'get':'list','post':'create'
})),
url(r'^student4/(?P<pk>\d+)',views.Students4API.as_view(actions={
'get':'retrieve','put':'update','delete':'destroy'
})),
4)ReadOnlyModelViewSet
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin。
# ReadOnlyModelViewSet对应get全部和get单个
class Student5API(ReadOnlyModelViewSet):
queryset = models.Student.objects
serializer_class = ser.StudentModelSerializer
# urls
url(r'^student5/$',views.Student5API.as_view(actions={'get':'list'})),
url(r'^student5/(?P<pk>\d+)',views.Student5API.as_view(actions={'get':'retrieve'})),
四、视图类继承关系
视图扩展类Mixin都是顶级继承
ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin 都继承自object
ViewSetMixin 它是视图集的顶级父类,所有视图集最终都继承它
GenericAPIView视图子类都继承它,也继承对应关系的视图扩展Mixin类
CreateAPIView,ListAPIView,UpdateAPIView,RetrieveAPIView,DestroyAPIView,ListCreateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView,RetrieveUpdateAPIView
通用视图子类继承关系
视图基类继承关系
GenericAPIView----》APIView----》View
视图集继承关系
xxx视图集继承关系查找方式:
我们可以先看名字,如果结尾是ViewSet,可以确定是一个视图集
普通视图集---》GenericViewSet----》ViewSetMixin
普通视图集也会继承对应的Mixin扩展类
比如ReadOnlyModelViewSet,是只读视图集,就是只有get全部和get单个的方法,那它必定还继承ListModelMixin和RetrieveModelMixin扩展类
总结:继承关系只要知道继承的方式就很好判断,所以要明白什么是视图集,什么是基类视图,什么是扩展类,通用视图和通用视图子类
drf请求、响应与视图的更多相关文章
- DRF的请求响应组件
目录 DRF的请求响应组件 请求模块(request) 概念 request源码简单分析 响应模块(response) 概念 使用方法 response源码简单分析: 解析模块(parse) 概念 使 ...
- 序列化多表操作、请求与响应、视图组件(子类与拓展类)、继承GenericAPIView类重写接口
今日内容概要 序列化多表操作 请求与相应 视图组件 内容详细 1.序列化多表操作 模型类 models.py中 # 新建django项目 # 创建表 模型类models.py中: from djang ...
- DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render
DRF框架 全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...
- drf复习(一)--原生djangoCBV请求生命周期源码分析、drf自定义配置文件、drf请求生命周期dispatch源码分析
admin后台注册model 一.原生djangoCBV请求生命周期源码分析 原生view的源码路径(django/views/generic/base.py) 1.从urls.py中as_view ...
- Django(48)drf请求模块源码分析
前言 APIView中的dispatch是整个请求生命过程的核心方法,包含了请求模块,权限验证,异常模块和响应模块,我们先来介绍请求模块 请求模块:request对象 源码入口 APIView类中di ...
- python---django请求-响应的生命周期(FBV和CBV含义)
Django请求的生命周期是指:当用户在访问该url路径是,在服务器Django后台都发生了什么. 客户端发送Http请求给服务端,Http请求是一堆字符串,其内容是: 访问:http://crm.o ...
- 第一篇 Flask基础篇之(配置文件,路由系统,模板,请求响应,session&cookie)
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后 ...
- laravel基础课程---8、laravel响应和视图(响应是什么)
laravel基础课程---8.laravel响应和视图(响应是什么) 一.总结 一句话总结: 就是向请求返回的响应数据(一般为html(视图),当然也可以是变量值):所有的路由及控制器必须返回某个类 ...
- 基于请求响应的MVC框架调用分析
一.使用Servlet来处理请求响应 当client提交数据之后.接着发送请求,请求被封装成对象,server接收到请求,依据请求的URL.来推断将请求对象交由哪个Servlet处理. 在servle ...
随机推荐
- 五月天的线上演唱会你看了吗?用Python分析网友对这场线上演唱会的看法
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:CDA数据分析师 豆瓣9.4分!这场线上演唱会到底多好看? 首先让我 ...
- Spring-AOP之工作实践(一)
案例一.角色校验 项目中,对某些方法需要用户具备指定角色权限才能执行. /** * 角色校验注解 */ @Retention(RetentionPolicy.RUNTIME) @Target(Elem ...
- 如何在微信小程序中使用骨架屏
先上效果图
- controlfile的情景恢复
控制文件测试 百度百科:控制文件(Control File)是Oracle的物理文件之一,它记录了数据库的名字.数据文件的位置等信息.控制文件的重要性在于,一旦控制文件损坏,数据库将会宕机.如果没有数 ...
- cb10a_c++_顺序容器的操作3关系运算符
cb10a_c++_cb09a_c++_顺序容器的操作3 2 顺序容器的操作3 3 关系运算符 4 所有的容器类型都可以使用 5 比较的容器必须具有相同的容器类型,double不能与int作比较 6 ...
- ca33a_demo_c++_新旧代码的兼容char数组与vector_string相互转换
/*ca33a_demo_c++33_CppPrimer_新旧代码的兼容_txwtech旧代码:数组和c风格字符串新代码:vector和string相互转换:c风格字符串<- ->stri ...
- snprintf和sprintf区别分析
目录[-] snprintf函数的返回值 snprintf函数的字符串缓冲 今天在项目中使用snprintf时遇到一个比较迷惑的问题,追根溯源了一下,在此对sprintf和snprintf进行一下对比 ...
- WeChair项目Alpha冲刺(8/10)
团队项目进行情况 1.昨日进展 Alpha冲刺第八天 昨日进展: 前端:安排页面美化,设计实名认证 后端:用户信息通过dao层存储数据库 数据库:修改数据表属性,与后端部署数据库交互 2.今日安 ...
- Python-17-作用域
python有一个名为vars的内置函数,它返回变量关联的不可见的字典: >>> x = 1 >>> scope = vars() >>> s ...
- StringEscapeUtils防止xss攻击详解
StringUtils和StringEscapeUtils这两个实用类. 1.转义防止xss攻击 1.转义可以分为下面的几种情况 第一用户输入特殊字符的时候,在提及的时候不做任何处理保持到数据库,当用 ...