drf之请求与响应,drf之视图组件,2个视图基类,5个视图扩展类,9个视图子类,视图集,源码分析ViewSetMixin
1.drf之请求与响应
在继承drf中的APIView时
Request
它的请求对象request就不是原来的那个request了(具体去看APIView源码分析),所以没钱请求的request都是一个新的对象,
这时我们便可以通过request.data取出全部数据,而原来的request是取不到request.data的,只能通过请求来看是取request.GET.get(k)或者request.POST.get(k)中的值且取不到put中的数据,
所以drf中的APIView是为了帮我们更好的拿到数据,其他的跟之前用起来一样,因为他们的底层都是继承了一个共同的父类View。
Response

在源码中有参数data,status,template_name,headers,content_typy(exception不看了)
其中data是将列表字典序列化之后以json的格式返回给前端(放在http响应的body中了)
status 响应状态码
template_name 就是前端模板
content_type 是用来响应前端返回的数据是什么类型的(有json,from/data,url类型)
drf能够解析的请求编码,响应编码
能够解析的请求编码和响应编码被放到drf中steeings的文件中了,这是drf的配置文件,我们可以在我们的项目中把其他模块配置文件中的值给写入到我们项目文件的配制文件底下,在这时这个数据就优先用我们配置文件底下的。
# drf配置中的源文件
DEFAULTS = { # Base API policies 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ], 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ] }
此时DEFAULT_PARSER_CLASSES的valve值就是前端返回给后端的格式只能是什么类型的,在项目的配制文件中加入代码接下来我们把json格式给注掉看下详情。
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.TemplateHTMLRenderer', ], 'DEFAULT_PARSER_CLASSES': [ # 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser', ], }
就会出现不让传json格式的数据
接下来DEFAULT_RENDERER_CLASSES是前端显示的格式,我们把json格式注掉之后,在postman中就直接返回前端的代码,同样的道理,把rest_framework注掉以后在前端就会返回json格式的数据
'DEFAULT_RENDERER_CLASSES': [ # 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.TemplateHTMLRenderer',

我们不仅仅可以在全局的设置里面修改这些配制,我们还可以在局部界面修改这些配置。这些与配置文件中都是一一对应的,一个不写,他就不会显示这种格式
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser from rest_framework.renderers import JSONRenderer,TemplateHTMLRenderer class TestView(APIView): parser_classes = [JSONParser, FormParser, MultiPartParser] class Tes_tView(APIView): renderers_classes = [JSONRenderer, TemplateHTMLRenderer]
上述优先级是自己局部页面加的配置,然后自己项目配置中,最后drf配置,这样优先级来执行。
2.drf之视图组件
自己去了解继承,封装和多态
3.两个视图基类
我们五个接口中大部分代码重复,我们就可以用drf中的GenericAPIView给写到一起,然后在分发下去,这就是两个视图基类,可以理解为基于GenericAPIView写接口
class BookViews(GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializers def get(self,request): book_list = self.get_queryset() res =BookSerializers(instance=book_list,many=True) return Response(res.data) def post(self,request): res = self.get_serializer(data=request.data) if res.is_valid(): res.save() return Response({'code':201,'msg':'添加成功'}) return Response({'code':201,'msg': res.errors}) class OneBookViews(GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializers def get(self,request,pk): book_list = self.get_object() res =self.get_serializer(instance=book_list) return Response(res.data) def put(self,request,pk): book_list = self.get_object() res = self.get_serializer(instance=book_list,data=request.data) if res.is_valid(): res.save() return Response({'code':201,'msg':'修改成功'}) return Response({'code':201,'msg': res.errors}) def delete(self,request,pk): self.get_queryset().filter(pk=pk).delete() return Response('')
4.五个视图扩展类
五个视图扩展类我们可以自己用代码来执行,也可以引用drf中的mixins来执行
class Get(GenericAPIView,ListModelMixin): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) class Post(GenericAPIView,CreateModelMixin): def post(self,request, *args, **kwargs): return self.create(request, *args, **kwargs) class OneGet(GenericAPIView,RetrieveModelMixin): def oneget(self,request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) class Put(GenericAPIView,UpdateModelMixin): def put(self,request, *args, **kwargs): return self.update(request, *args, **kwargs) class Delete(GenericAPIView,DestroyModelMixin): def delete(self,request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
如果不想引用Mixin就可以把两个视图基类拔下来直接放到每个视图扩展类下面就行,下面我们来看ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin。
(1)ListModelMixin源码(get查多个)
class ListModelMixin: """ List a queryset. """ def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
(2)CreateModelMixin源码(post)
class CreateModelMixin: """ 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) return Response(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 {}
(3)RetrieveModelMixin源码 (get查一个)
class RetrieveModelMixin: """ Retrieve a model instance. """ def retrieve(self, request, *args, **kwargs): instance = self.get_object() serializer = self.get_serializer(instance) return Response(serializer.data)
(4)UpdateModelMixin源码(put)
class UpdateModelMixin: """ 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 = {} return Response(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)
(5)DestroyModelMixin源码(delete)
class DestroyModelMixin: """ Destroy a model instance. """ def destroy(self, request, *args, **kwargs): instance = self.get_object() self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) def perform_destroy(self, instance): instance.delete()
5.9个视图子类
9个视图子类就是把包含上面的五个视图扩展类以及他们的拼接,自己继承就行
class Get(GenericAPIView,ListModelMixin): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) class Post(GenericAPIView,CreateModelMixin): def post(self,request, *args, **kwargs): return self.create(request, *args, **kwargs) class OneGet(GenericAPIView,RetrieveModelMixin): def oneget(self,request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) class Put(GenericAPIView,UpdateModelMixin): def put(self,request, *args, **kwargs): return self.update(request, *args, **kwargs) class Delete(GenericAPIView,DestroyModelMixin): def delete(self,request, *args, **kwargs): return self.destroy(request, *args, **kwargs) # 增加,查询 class Get_Post(Get,Post): pass # 修改并查询 class OneGet_Put(OneGet,Put): pass # 删除并查询 class OneGet_Delete(OneGet,Delete): pass # 修改删除查询 class OneGet_Put_Delete(OneGet,Put,Delete): pass # 全部 class All(Get,Post,OneGet,Put,Delete): pass
6.视图集
我自己写的
View.py
class BookViews(All): queryset = Book.objects.all() serializer_class = BookSerializers def get(self,request,pk): try: int(pk) get = super().oneget(request,pk) except: get = super().get(request) return Response(get.data) def post(self,request,pk): get = super().post(request,pk) return Response(get) def put(self,request,pk): get = super().put(request,pk) return Response(get) def delete(self,request,pk): get = super().delete(request,pk) return Response(get)
urls.py re_path('^books/((?P<pk>[1-9]\d*)/|)', views.BookViews.as_view())
我是匹配到同一个路由上面,接下来我们用一个视图集匹配到两个路由上面,这时我们就需要用到ReadOnlyModelViewSet,此时我们的代码可以精简为
View.py
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet class BookViews(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializers
urls.py path('books/', views.BookViews.as_view({'get': 'list', 'post': 'create'})), path('books/<int:pk>/', views.BookViews.as_view({'get': 'retrieve', 'put': 'update','delete': 'destroy'})),
@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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通