Django的rest_framework的視圖之Mixin類編寫視圖源碼解析

  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對象
  
  下面咱們一個一個來看下面的類
  
  一、看下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方法的返回結果就是咱們想要的結果
  
  二、在來看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方法保存
  
  三、而後來看下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方法返回咱們要查詢的結果
  
  四、而後咱們在看下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函數的返回值就能夠了
  
  五、最後看下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)api

相關文章
相關標籤/搜索