drf之请求与响应
继承APIView后,请求对象request中,每一次请求都是一个新的request
- Request类:属性或方法
1.REST framework传入视图的request对象不再是django默认的HttpResquest对象,而是REST framework提供的扩展了HttpResquest类的Request类的对象。
2.REST framework提供了Parser解析器,在接收到请求后会自动根据Content-Type,指名的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为字典[QueryDict]对象保存到Request对象中。
3.Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果
4.无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据 - Data
1.request.data返回解析之后的请求体数据。类似于django中标准的request.POST和request.FILES属性,但提供如下特性:
2.包含了解析之后的文件和非文件数据
3.包含了对POST、PUT、PATCH请求方式解析的数据
4.利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
注意:原生djagno,put提交的数据在request.POST中是取不到的
- Query_params
其他的用起来跟之前一样用(FILES,method,path....)底层原理__getattr__
Response类
REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
REST framework提供了Renderer渲染器,用来根据请求头中的Accept(接受数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置文件修改相应格式。
- 参数说明
data=None, # 字典,列表 序列化成json格式字符串,返回给前端(放在http响应的body中了)
status=None, # http 响应的状态码,默认是200,201
drf帮咱们把所有的http响应状态码都做成了常量,可以直接导进来用
headers=None, # http的响应头,字典 {name:lqz}
template_name=None, # 了解:在浏览器中看到好看的页面,指定的模板
content_type=None, # 响应的编码格式(json)
- 原生django要在响应头中加数据
dic = {'name':'joker','age':18}
res = JsonResponse(d)
res['rrr'] = 'yyyy'
return res
- 配置
可以在rest_framework.settings查找所有的drf默认配置项
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
'rest_framework.renderers.JSONRenderer', # json渲染器
'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器
)
}
drf能够解析的请求编码,响应编码
能够解析的请求编码
- 默认能解析:
urlencoded
form-data
json
项目中没有配置,是因为在drf内置的配置文件中提前配好了
drf也是有两套,一套是项目中的配置(settings.py),一套是默认的配置
drf的配置文件settings.py中有DEFAULT_PARSER_CLASSES(默认的解析类)
'rest_framework.parsers.JSONParser', # 可以解析json格式
'rest_framework.parsers.FormParser', # 可以解析urlencoded格式
'rest_framework.parsers.MultiPartParser' # 可以解析form-data格式
想让我们的接口只能接受json格式
- 方式一:全局配置,到项目配置文件。以后所有的接口都遵循这个配置
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser', # 不支持form-data格式
],
}
- 方式二:局部配置
class TestView(APIView):
parser_classes = [JSONParser,FormParser,MultiPartParser] # 在视图类中指定json格式编码格式,后续配置文件,drf配置文件的设置都失效
总结:
解析类的使用顺序:优先用视图类自己的,然后用项目配置文件,最后用内置的
实际项目如何配置
基本上都运行JSONParser,FormParser
如果上传文件只允许MultiPartParser
响应编码
如果用浏览器有好看的样子,如果用postman只看到json格式
默认请情况下,响应的编码是根据客户端类型决定的
- 全局配置:在项目的配置文件
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
# 'rest_framework.renderers.JSONRenderer', # json格式
'rest_framework.renderers.BrowsableAPIRenderer', # 浏览器的格式
]
}
- 局部配置:
class TestView(APIView):
renderer_classes = [JSONRenderer,]
实际编码中,响应一般步配,就用默认
drf之视图组件
由于drf提供了一个顶层的视图类APIView,咱们可以通过继承APIView写视图类
后期咱们要写的代码可能重复代码比较多,就可以使用面向对象的继承,封装
两个视图基类
- APIView
- GenericAPIView(继承了APIView)
APIView
APIView是REST framework提供的所有视图的基类,继承自Django的View父类
APIView与View的不同之处在于
1.传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
2.视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
3.任何APIException异常都会被捕获到,并且处理成合适的响应信息;
4.在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
支持定义的类属性
1.authentication_classes 列表或元祖,身份认证类
2.permissoin_classes 列表或元祖,权限检查类
3.throttle_classes 列表或元祖,流量控制类
GenericAPIView
GenericAPIView--->继承了APIView
类属性
queryset = User.objects.all() # 指明使用的数据查询集
serializer_class = UserSerializer # 指明视图使用的序列化器
方法
self.get_object() # 根据pk获取单个数据
self.get_serializer # 获取要使用的序列化类
self.get_queryset() # 获取所有要序列化数据
基于APIView写5个接口
class UserView(GenericAPIView):
# 配置两个 类属性
queryset = User.objects.all()
serializer_class = UserSerializer
# def get_queryset(self):
# if self.request.method=='GET':
# return User.objects.all()
# else:
# return Publish.object.all()
def get(self, request):
res_list = self.get_queryset() # 提高扩展性
ser = self.get_serializer(instance=res_list, many=True)
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "新增成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
class UserDetailView(GenericAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request, pk):
# obj = self.get_queryset().filter(pk=pk).first()
# queryset.get({'pk':'有名分组分出来的'}
obj = self.get_object() # 根据传入的pk,获取一条数据
ser = self.get_serializer(instance=obj)
return Response(ser.data)
def put(self, request, pk):
obj = self.get_object()
ser = self.get_serializer(instance=obj, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "修改成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
self.get_queryset().filter(pk=pk).delete()
return Response('')
基于GenericAPIView写5个接口
必须配合GenericAPIView使用,不能配合APIView使用
from rest_framework.mixins import RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, \
ListModelMixin
"""
CreateModelMixin:写了一个Create方法,就是原来咱们post中的代码
RetrieveModelMixin:retrieve,就是咱们原来的get
UpdateModelMixin:update方法,就是咱们原来的put
ListModelMixin:list方法,就是原来咱们的get
DestroyModelMixin:destroy方法,就是原来咱们的delete
"""
class UserView(GenericAPIView, ListModelMixin, CreateModelMixin):
# 配置两个 类属性
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *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)
9个视图子类
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
视图集
继承ModelViewSet编写5个接口
- 视图类
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class UserView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
- 路由
path('user/', views.UserView.as_view({'get': 'list', 'post': 'create'})),
path('user/<int:pk>', views.UserView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
源码分析ViewSetMixin
@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
总结
#两个基类
APIView
GenericAPIView:有关数据库操作,queryset 和serializer_class
# 5个视图扩展类(rest_framework.mixins)
CreateModelMixin:create方法创建一条
DestroyModelMixin:destory方法删除一条
ListModelMixin:list方法获取所有
RetrieveModelMixin:retrieve获取一条
UpdateModelMixin:update修改一条
# 9个子类视图(rest_framework.generics)
CreateAPIView: 继承CreateModelMixin,GenericAPIView,有post方法,新增数据
DestroyAPIView:继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
ListAPIView:继承ListModelMixin,GenericAPIView,有get方法获取所有
UpdateAPIView:继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
RetrieveAPIView:继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条
ListCreateAPIView:继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
RetrieveDestroyAPIView:继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
RetrieveUpdateAPIView:继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除
#视图集
ViewSetMixin:重写了as_view
ViewSet: 继承ViewSetMixin和APIView
GenericViewSet:继承ViewSetMixin, generics.GenericAPIView
ModelViewSet:继承mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet
ReadOnlyModelViewSet:继承mixins.RetrieveModelMixin,mixins.ListModelMixin,GenericViewSet
posted on
浙公网安备 33010602011771号