drf之请求与响应Request
from rest_framework.request import Request
def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None): # 二次封装request,将原生request作为drf request对象的 _request 属性 self._request = request def __getattr__(self,item): return getattr(self._request,item)
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
Request类:属性或方法
# 请求对象.data:前端以三种编码方式传入的数据,都可以取出来# 请求对象.query_params 与Django标准的request.GET相同,只是更换了更正确的名称而已。
Response
from rest_framework.response import Response
REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。REST framework提供了Renderer 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。
Response类:属性或方法
def __init__(self, data=None, status=None, template_name=None, headers=None, exception=False, content_type=None): #data:你要返回的数据,字典#status:返回的状态码,默认是200,-from rest_framework import status在这个路径下,它把所有使用到的状态码都定义成了常量#template_name 渲染的模板名字(自定制模板),不需要了解#headers:响应头,可以往响应头放东西,就是一个字典#content_type:响应的编码格式,application/json和text/html;
drf能够解析的请求编码,响应编码响应状态码
# 正常返回信息1xx HTTP_100_CONTINUEHTTP_101_SWITCHING_PROTOCOLS# 返回成功2xxHTTP_200_OKHTTP_201_CREATEDHTTP_202_ACCEPTEDHTTP_203_NON_AUTHORITATIVE_INFORMATIONHTTP_204_NO_CONTENTHTTP_205_RESET_CONTENTHTTP_206_PARTIAL_CONTENTHTTP_207_MULTI_STATUS# 重定向3xxHTTP_300_MULTIPLE_CHOICESHTTP_301_MOVED_PERMANENTLYHTTP_302_FOUNDHTTP_303_SEE_OTHERHTTP_304_NOT_MODIFIEDHTTP_305_USE_PROXYHTTP_306_RESERVEDHTTP_307_TEMPORARY_REDIRECT# 客户端错误4xxHTTP_400_BAD_REQUESTHTTP_401_UNAUTHORIZEDHTTP_402_PAYMENT_REQUIREDHTTP_403_FORBIDDENHTTP_404_NOT_FOUNDHTTP_405_METHOD_NOT_ALLOWEDHTTP_406_NOT_ACCEPTABLEHTTP_407_PROXY_AUTHENTICATION_REQUIREDHTTP_408_REQUEST_TIMEOUTHTTP_409_CONFLICTHTTP_410_GONEHTTP_411_LENGTH_REQUIREDHTTP_412_PRECONDITION_FAILEDHTTP_413_REQUEST_ENTITY_TOO_LARGEHTTP_414_REQUEST_URI_TOO_LONGHTTP_415_UNSUPPORTED_MEDIA_TYPEHTTP_416_REQUESTED_RANGE_NOT_SATISFIABLEHTTP_417_EXPECTATION_FAILEDHTTP_422_UNPROCESSABLE_ENTITYHTTP_423_LOCKEDHTTP_424_FAILED_DEPENDENCYHTTP_428_PRECONDITION_REQUIREDHTTP_429_TOO_MANY_REQUESTSHTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGEHTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS# 客户端错误5xxHTTP_500_INTERNAL_SERVER_ERRORHTTP_501_NOT_IMPLEMENTEDHTTP_502_BAD_GATEWAYHTTP_503_SERVICE_UNAVAILABLEHTTP_504_GATEWAY_TIMEOUTHTTP_505_HTTP_VERSION_NOT_SUPPORTEDHTTP_507_INSUFFICIENT_STORAGEHTTP_511_NETWORK_AUTHENTICATION_REQUIRED
请求编码
能够解析的请求编码
默认能够解析: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', ], }方式二:局部配置class TestView(APIView): parser_classes = [JSONParser,FormParser,MultiPartParser]
总结
解析类的使用顺序:优先用视图类自己的,然后用项目配置文件,最后用内置的实际项目如何配置: -基本上都运行JSONParser,FormParser -如果上传文件只允许MultiPartParser
drf之视图组件
由于drf提供了一个顶层的视图类APIView,我们可以通过继承APIView写视图类
但是后期我们可能需要序列化的表比较多,这可能就需要我们重复的书写视图函数的五个接口,这时候我们就可以使用面向对象的继承,封装,使用GenericAPIView进行书写视图函数的5个接口
2个视图基类
# APIView# GenericAPIView-->继承了APIView-类属性: queryset = User.objects.all() serializer_class = UserSerializer -方法: self.get_object() # 根据pk获取单个数据 self.get_serializer # 获取要使用的序列化类 self.get_queryset() # 获取所有要序列化数据
原来我们基于apiview写的5个接口是这样的:
class UserView(APIView): def get(self, request): book_list = User.objects.all() ser = UserSerializer(instance=book_list, many=True) return Response(ser.data) def post(self, request): ser = UserSerializer(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(APIView): def get(self, request, pk): book = User.objects.filter(pk=pk).first() ser = UserSerializer(instance=book) return Response(ser.data) def put(self, request, pk): book = User.objects.filter(pk=pk).first() ser = UserSerializer(instance=book, 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): User.objects.filter(pk=pk).delete() return Response('{'code': 100, 'msg': '删除成功'}')
现在我们基于GenericAPIView写5个接口:
queryset = User.objects.all()
serializer_class = UserSerializer
对于不同的模型表,开设的接口我们只需要该上面两行代码就行
from rest_framework.generics import GenericAPIViewclass UserView(GenericAPIView): queryset = User.objects.all() serializer_class = UserSerializer def get(self, request): book_list = self.get_queryset() ser = self.get_serializer(instance=book_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): book = self.get_object() ser = self.get_serializer(instance=book) return Response(ser.data) def put(self, request, pk): book = self.get_object() ser = self.get_serializer(instance=book, 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('{'code': 100, 'msg': '删除成功'}')
进一步优化:基于GenericAPIView和5个视图扩展类写的接口
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin# views.pyclass Book3View(GenericAPIView,ListModelMixin,CreateModelMixin): queryset=Book.objects serializer_class = BookSerializer def get(self,request): return self.list(request) def post(self,request): return self.create(request)class Book3DetailView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin): queryset = Book.objects serializer_class = BookSerializer def get(self, request,pk): return self.retrieve(request,pk) def put(self, request,pk): return self.update(request,pk) def delete(self,request,pk): return self.destroy(request,pk)# urls.py # 使用GenericAPIView+5 个视图扩展类 重写的 path('books3/', views.Book3View.as_view()), re_path('books3/(?P\d+)', views.Book3DetailView.as_view()),
再进一步优化:使用ModelViewSet编写5个接口
# views.py from rest_framework.viewsets import ModelViewSetclass Book5View(ModelViewSet): #5个接口都有,但是路由有点问题 queryset = Book.objects serializer_class = BookSerializer # urls.py# 使用ModelViewSet编写5个接口 path('books5/', views.Book5View.as_view(actions={'get':'list','post':'create'})), #当路径匹配,又是get请求,会执行Book5View的list方法 re_path('books5/(?P\d+)', views.Book5View.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),