Django(55)GenericAPIView源碼分析


源碼分析

GenericAPIView繼承自APIView,也就是在APIView基礎上再做了一層封裝,源碼如下:

class GenericAPIView(views.APIView):
    queryset = None
    serializer_class = None

    lookup_field = 'pk'
    lookup_url_kwarg = None

    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

    def get_queryset(self):
        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):
            queryset = queryset.all()
        return queryset

    def get_object(self):
        queryset = self.filter_queryset(self.get_queryset())

        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)

        self.check_object_permissions(self.request, obj)

        return obj

    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        kwargs.setdefault('context', self.get_serializer_context())
        return serializer_class(*args, **kwargs)

    def get_serializer_class(self):
        assert self.serializer_class is not None, (
            "'%s' should either include a `serializer_class` attribute, "
            "or override the `get_serializer_class()` method."
            % self.__class__.__name__
        )

        return self.serializer_class

    def get_serializer_context(self):
        return {
            'request': self.request,
            'format': self.format_kwarg,
            'view': self
        }

    def filter_queryset(self, queryset):
        for backend in list(self.filter_backends):
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

    @property
    def paginator(self):
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        return self._paginator

    def paginate_queryset(self, queryset):
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)

    def get_paginated_response(self, data):
        assert self.paginator is not None
        return self.paginator.get_paginated_response(data)

我們可以看到GenericAPIView中定義了6個類屬性和8個方法,接下來一個個分析
 

類屬性

  • queryset = None
  • serializer_class = None
  • lookup_field = 'pk'
  • lookup_url_kwarg = None
  • filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
  • pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
     

queryset

  queryset是用來控制視圖返回給前端的數據。如果沒什么邏輯,可以直接寫在視圖的類屬性中,如果邏輯比較復雜,也可以重寫get_queryset方法用來返回一個queryset對象。如果重寫了get_queryset,那么以后獲取queryset的時候就需要通過調用get_queryset方法。因為queryset 這個屬性只會調用一次,以后所有的請求都是使用他的緩存。
 

serializer_class

  serializer_class用來驗證和序列化數據的。也是可以通過直接設置這個屬性,也可以通過重寫get_serializer_class來實現。
 

lookup_field

在檢索的時候,根據什么參數進行檢索。默認是pk,也就是主鍵。
 

lookup_url_kwarg

在檢索的url中的參數名稱。默認沒有設置,跟lookup_field保持一致。
 

filter_backends

用於過濾查詢集的過濾器后端類的列表。默認值與DEFAULT_FILTER_BACKENDS 設置的值相同。
 

pagination_class

當分頁列出結果時應使用的分頁類。默認值與 DEFAULT_PAGINATION_CLASS 設置的值相同,即 'rest_framework.pagination.PageNumberPagination'
 

方法

  • get_queryset
  • get_object
  • get_serializer
  • get_serializer_class
  • get_serializer_context
  • filter_queryset
     

get_queryset

def get_queryset(self):
    # 斷言queryset是否不為None
    assert self.queryset is not None, (
        "'%s' should either include a `queryset` attribute, "
        "or override the `get_queryset()` method."
        % self.__class__.__name__
    )
    
    # 定義queryset屬性,獲取父類的queryset,如果父類沒有定義類屬性`queryset`,那么默認值就是None,就會報上面斷言的錯誤 
    queryset = self.queryset
    # 如果queryset是QuerySet對象,那么返回全部內容
    if isinstance(queryset, QuerySet):
        queryset = queryset.all()
    # 如果不是queryset,那么直接返回
    return queryset

get_queryset默認是返回數據庫全部數據,如果想返回其他數據,需要自定義
 

get_object

def get_object(self):
    queryset = self.filter_queryset(self.get_queryset())
    
    # 查找過濾的條件,默認是pk
    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)
    
    # 可能會引發權限被拒絕
    self.check_object_permissions(self.request, obj)

    return obj

該方法是用於在數據檢索(通過pk查找)的時候,返回一條數據的。
 

get_serializer

def get_serializer(self, *args, **kwargs):
    serializer_class = self.get_serializer_class()
    kwargs.setdefault('context', self.get_serializer_context())
    return serializer_class(*args, **kwargs)

返回應該用於驗證和反序列化輸入以及序列化輸出的序列化器實例
 

get_serializer_class

def get_serializer_class(self):
    assert self.serializer_class is not None, (
        "'%s' should either include a `serializer_class` attribute, "
        "or override the `get_serializer_class()` method."
        % self.__class__.__name__
    )

    return self.serializer_class

返回用於序列化的類。默認使用self.serializer_class。如果您需要根據傳入請求提供不同的序列化,您可能需要重寫它。
 

get_serializer_context

def get_serializer_context(self):
    return {
        'request': self.request,
        'format': self.format_kwarg,
        'view': self
    }

提供給序列化的額外上下文。
 

filter_queryset

def filter_queryset(self, queryset):
    for backend in list(self.filter_backends):
        queryset = backend().filter_queryset(self.request, queryset, self)
    return queryset

給定一個查詢集,使用正在使用的過濾器對其進行過濾。您不太可能想要覆蓋此方法,但如果您想將配置的過濾后端應用到默認查詢集,您可能需要從列表視圖或自定義get_object 方法中調用它。
 

實戰案例

class StudentsGenericView(GenericAPIView):
    queryset = Student.objects.all()  # 定義了類屬性queryset,告訴視圖要針對哪個模型做處理
    serializer_class = StudentModelSerializer  # 定義類屬性serlializer_class,告訴視圖你的序列化的類是什么
    def get(self, request, *args, **kwargs):
        pk = kwargs.get("pk")
        if pk:
            many = False
            query = self.get_object()  # 通過pk檢索數據,返回一條數據
        else:
            many = True
            query = self.get_queryset()  # 返回動態的數據集,默認返回全部
        serializer = self.get_serializer(query, many=many)  # 如果數據對象是queryset對象,many需要為True
        return APIResponse(results=serializer.data)


免責聲明!

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



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