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)

  

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM