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個模組
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, *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 {}
下面我們來分析一下程式碼
首先這裡有個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)