文档章节

Django的rest_framework的视图之Mixin类编写视图源码解析

SEOwhywhy
 SEOwhywhy
发布于 03/03 10:24
字数 1715
阅读 6
收藏 0

  Django的rest_framework的视图之Mixin类编写视图源码解析
  
  Mixin类编写视图
  
  我们这里用auther表来做演示,先为auther和autherdetail写2个url
  
  url(r'^autherdetail/(?P<id>\d+)', views.Book_detail_cbv.as_view(), name="autherdetail"),
  
  url(r'^auther/', views.Book_cbv.as_view(),name="auther"),
  
  然后分别为这2个类写对应的序列化的类
  
  class authermodelserializer(serializers.ModelSerializer):
  
  class Meta:
  
  model = models.Auther
  
  fields = "__all__"
  
  下面我们开写视图函数
  
  需要在view文件中导入2个模块
  
  1
  
  2
  
  from rest_framework import mixins
  
  from rest_framework import generics
  
  先介绍一下mixins类,我们主要用mixins类来对queryset对象或者model对象做操作
  
  mixins.ListModelMixin
  
  这个是用来显示queryset的数据
  
  mixins.CreateModelMixin
  
  这个用来创建一条model对象
  
  mixins.RetrieveModelMixin
  
  这个是用来显示一个model对象
  
  mixins.DestroyModelMixin
  
  这个是用来删除一个model对象
  
  mixins.UpdateModelMixin
  
  这个是用来更新一个model对象
  
  下面我们一个一个来看下面的类
  
  1、看下mixins.ListModelMixin
  
  这个类就只有一个方法,list方法,我们看下面的代码其实很熟悉,就是把一个queryset对象做序列化后,然后把序列化后的结果返回
  
  class ListModelMixin(object):
  
  """
  
  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)
  
  我们这里看到get_serializer中的参数有个queryset,那么这个queryset是什么呢?
  
  通过上面的图,我们大致可以猜到,是由self.get_queryset()这个方法返回的结果,那么这个方法又干了什么呢?
  
  首先我们要清楚self是什么?
  
  从上面的图我们知道,self其实就是Auther_view这个类的实例对象,这个实例对象根本就没有get_queryset这个方法,但是由于这个类继承了3个类,我们一个一个找,最终在
  
  generics.GenericAPIView这个类中找到了get_queryset这个方法
  
  def get_queryset(self):
  
  """
  
  Get the list of items for this view.
  
  This must be an iterable, and may be a queryset.
  
  Defaults to using `self.queryset`.
  
  This method should always be used rather than accessing `self.queryset`
  
  directly, as `self.queryset` gets evaluated only once, and those results
  
  are cached for all subsequent requests.
  
  You may want to override this if you need to provide different
  
  querysets depending on the incoming request.
  
  (Eg. return a list of items that is specific to the user)
  
  """
  
  assert self.queryset is not None, (
  
  "'%s' should either include a `queryset` attribute, "
  
  "or override the `get_queryset()` method."
  
  % self.__class__.__name__
  
  )
  
  queryset = self.queryset
  
  if isinstance(queryset, QuerySet):
  
  # Ensure queryset is re-evaluated on each request.
  
  queryset = queryset.all()
  
  return queryset
  
  我们可以很清晰的看到get_queryset这个方法返回的结果就是self.queryset
  
  那么self.queryset这个是什么呢?
  
  我们在Auhter_view这个类中已经定义了这个类变量,所以我们这里定义的2个类变量的名称是固定的,不能随意修改的,属于配置项
  
  下面我们走的流程就和之前差不多了
  
  先定义get请求的处理的函数
  
  因为mixins.ListModelMixin这个类是为了显示queryset对象的类,那么下面我们进入这个类
  
  所以我们在get方法中,直接调用list方法的返回结果就是我们想要的结果
  
  2、在来看mixin.CreateModelMixin类
  
  这个类是为了创建一个model对象
  
  首先进入这个类,看下具体的代码
  
  class CreateModelMixin(object):
  
  """
  
  Create a model instance.
  
  """
  
  def create(self, request,www.wujirongyaoy.com *args, **kwargs):
  
  serializer = self.get_serializer(data=request.data)
  
  serializer.is_valid(raise_www.yongshiyule178.com exception=True)
  
  self.perform_create( www.dfgjpt.com serializer)
  
  headers = self.get_success_headers(serializer.www.feifanyule.cn data)
  
  return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
  
  def perform_create(self, www.jiahuayulpt.com serializer):
  
  serializer.save()
  
  def get_success_headers(self, data):
  
  try:
  
  return {'Location': www.yongshi123.cn str(data[api_settings.URL_FIELD_NAME])}
  
  except (TypeError, www.dashuj5.com KeyError):
  
  return {}
  
  下面我们来分析一下代码
  
  首先这里有个self.get_serializer方法,这个方法也在generics.GenericAPIView类中
  
  下面我们在来看下get_serializer方法
  
  def get_serializer(self, *args, **kwargs):
  
  """
  
  Return the serializer instance that should be used for validating and
  
  deserializing input, and for serializing output.
  
  """
  
  serializer_class = self.get_serializer_class()
  
  kwargs['context'] = self.get_serializer_context()
  
  return serializer_class(*args, **kwargs)
  
  我们在来看下get_serializer_class这个方法
  
  我们看到非常清楚,这个函数的返回值就是我们先前定义个serializer_class的类变量,所以这个类变量的名称也不能修改,必须要这么写,属于一个配置类的变量
  
  流程我们已经梳理清楚了,下面我们在看下post请求的视图函数
  
  post请求调用的mixins.CreateModelMixin类中的create方法
  
  class CreateModelMixin(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)
  
  return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
  
  最后我们在看下perform.create这个方法,是不是很熟悉了,调用save方法保存
  
  3、然后来看下mixins.RetriveModelMixin类
  
  先看下这个类的代码
  
  class RetrieveModelMixin(object):
  
  """
  
  Retrieve a model instance.
  
  """
  
  def retrieve(self, request, *args, **kwargs):
  
  instance = self.get_object()
  
  serializer = self.get_serializer(instance)
  
  return Response(serializer.data)
  
  然后在来看下get_object这个方法干了什么,这个方法同样在generics.GenericAPIView类中,我们一猜就知道这个方法是获取一个model对象,然后对这个model对象进行序列化处理
  
  def get_object(self):
  
  """
  
  Returns the object the view is displaying.
  
  You may want to override this if you need to provide non-standard
  
  queryset lookups.  Eg if objects are referenced using multiple
  
  keyword arguments in the url conf.
  
  """
  
  queryset = self.filter_queryset(self.get_queryset())
  
  # Perform the lookup filtering.
  
  lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
  
  assert lookup_url_kwarg in self.kwargs, (
  
  'Expected view %s to be called with a URL keyword argument '
  
  'named "%s". Fix your URL conf, or set the `.lookup_field` '
  
  'attribute on the view correctly.' %
  
  (self.__class__.__name__, lookup_url_kwarg)
  
  )
  
  filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
  
  obj = get_object_or_404(queryset, **filter_kwargs)
  
  # May raise a permission denied
  
  self.check_object_permissions(self.request, obj)
  
  return obj
  
  我们看到这个方法确实返回一个obj对象
  
  最后看下get请求,调用mixins。RetrieveModelMixin类中的retieve方法返回我们要查询的结果
  
  4、然后我们在看下mixins.DestroyModelMixin类
  
  直接拿到model独享,然后调用perform_destory方法删除这个model对象
  
  class DestroyModelMixin(object):
  
  """
  
  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()
  
  然后我们在看下视图函数中是如何处理delete请求的
  
  class Autherdetail_view(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
  
  queryset = models.Auther.objects.all()
  
  serializer_class = authermodelserializer
  
  def get(self,request,*args,**kwargs):
  
  return self.retrieve(request,*args,**kwargs)
  
  def delete(self,request,*args,**kwargs):
  
  return self.destroy(request,*args,**kwargs)
  
  直接返回mixins.DestoryModelMixins的detory函数的返回值就可以了
  
  5、最后看下mixins.UpdateModelMixin类
  
  同样,先获取model对象,然后获取序列化类,然后把model对象和request.data一起传递给序列化类
  
  序列化类在调用调用sava方法保存数据
  
  class UpdateModelMixin(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 = {}
  
  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)
  
  我们在看put请求的视图函数
  
  class Autherdetail_view(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
  
  queryset = models.Auther.objects.all()
  
  serializer_class = authermodelserializer
  
  def get(self,request,*args,**kwargs):
  
  return self.retrieve(request,*args,**kwargs)
  
  def delete(self,request,*args,**kwargs):
  
  return self.destroy(request,*args,**kwargs)
  
  def put(self,request,*args,**kwargs):
  
  return self.update(request,*args,**kwargs)

© 著作权归作者所有

SEOwhywhy
粉丝 9
博文 155
码字总数 342404
作品 0
私信 提问
Django rest framework 认证组件源码分析

基础知识 想要弄清楚rest framework的执行过程首先需要明白Django中CBV和FBV执行流程,http请求最最本质的就是一个socket,一个请求过来第一步就是做路由匹配,在FBV中因为视图本身就是一个函...

FanMLei
2018/11/27
0
0
Django REST framework 中 3 种类视图的对比

相较于使用基于方法(function based)的视图,我们更加倾向使用基于类(class based)的视图。接 下来,你将看到这是一个强大的模式,是我们能够重用公共的功能,并且,帮我们减少重复的造轮...

xjtuhit
2017/11/14
0
0
Django 基于类的视图源码分析 一

基于类的视图(Class-based view)是Django 1.3引入的新的视图编写方式,用于取代以前基于函数(Function-based)方式。借助于OO和Python中方便的多重继承特性,基于类的视图可以提供更好的抽象与...

XuYuan
2013/02/05
547
0
Django基于类的视图

django 1.8 官方文档翻译: 3-4-1 基于类的视图 https://segmentfault.com/a/1190000003506222 基于类的视图 视图是一个可调用对象,它接受一个请求然后返回一个响应。 基于类的视图优点 HT...

人间四月
2016/04/11
114
0
基于Django实现 RESTful API 之RestFramework框架

一、首先什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角度类审视整个网络,它将分布在...

SlashBoyMr_wang
2018/09/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

PostgreSQL 11.3 locking

rudi
今天
5
0
Mybatis Plus sql注入器

一、继承AbstractMethod /** * @author beth * @data 2019-10-23 20:39 */public class DeleteAllMethod extends AbstractMethod { @Override public MappedStatement injectMap......

一个yuanbeth
今天
10
1
一次写shell脚本的经历记录——特殊字符惹的祸

本文首发于微信公众号“我的小碗汤”,扫码文末二维码即可关注,欢迎一起交流! redis在容器化的过程中,涉及到纵向扩pod实例cpu、内存以及redis实例的maxmemory值,statefulset管理的pod需要...

码农实战
今天
4
0
为什么阿里巴巴Java开发手册中不建议在循环体中使用+进行字符串拼接?

之前在阅读《阿里巴巴Java开发手册》时,发现有一条是关于循环体中字符串拼接的建议,具体内容如下: 那么我们首先来用例子来看看在循环体中用 + 或者用 StringBuilder 进行字符串拼接的效率...

武培轩
今天
8
0
队列-链式(c/c++实现)

队列是在线性表功能稍作修改形成的,在生活中排队是不能插队的吧,先排队先得到对待,慢来得排在最后面,这样来就形成了”先进先出“的队列。作用就是通过伟大的程序员来实现算法解决现实生活...

白客C
今天
80
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部