Django REST framework (DRF) 中 GenericAPIView
的源碼核心部分。
- 它是所有“泛型視圖”的基礎類,比如常用的
ListAPIView
、RetrieveAPIView
、CreateAPIView
都是繼承自它。
🌟 作用
-
繼承自
APIView
,因此仍然是一個標準的 DRF 視圖。 -
提供了常用的“通用邏輯”:
- 統一獲取 queryset
- 統一獲取 serializer
- 提供 對象查找(
get_object
) - 提供 分頁(
paginate_queryset
/get_paginated_response
) - 提供 過濾(
filter_queryset
)
-
它本身不實現
get/post/put/delete
等 HTTP 方法,而是作為“基類”讓子類在此之上去擴展。
🔑 關鍵點解析
1. queryset
和 get_queryset
def get_queryset(self):assert self.queryset is not Nonequeryset = self.querysetif isinstance(queryset, QuerySet):queryset = queryset.all() # 確保每次請求都是新 QuerySetreturn queryset
- 必須設置
queryset
或重寫get_queryset
。 - 一般推薦重寫
get_queryset
來根據 用戶/請求參數 動態返回不同數據。 - 注意不要直接用
self.queryset
,否則會因為緩存導致跨請求數據不一致。
2. serializer_class
和 get_serializer_class
def get_serializer(self, *args, **kwargs):serializer_class = self.get_serializer_class()kwargs.setdefault('context', self.get_serializer_context())return serializer_class(*args, **kwargs)
- 必須指定
serializer_class
或重寫get_serializer_class
。 - 可以根據用戶角色、請求方法等動態選擇不同序列化器。
3. get_object
def get_object(self):queryset = self.filter_queryset(self.get_queryset())lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_fieldfilter_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
- 用來獲取某一個具體對象(常用于
RetrieveAPIView
、UpdateAPIView
)。 - 默認按
pk
查找,可以改lookup_field = 'slug'
之類。 - 自動做 權限檢查。
4. 過濾與分頁
filter_queryset(queryset)
:遍歷filter_backends
,按配置的 filter backend 處理,比如DjangoFilterBackend
、SearchFilter
、OrderingFilter
。paginate_queryset(queryset)
:按pagination_class
分頁,比如PageNumberPagination
。get_paginated_response(data)
:返回帶分頁信息的 Response。
? 使用示例
比如寫一個獲取用戶文章的 API:
from rest_framework.generics import ListAPIView, RetrieveAPIView
from .models import Article
from .serializers import ArticleSerializerclass ArticleListView(ListAPIView):serializer_class = ArticleSerializerdef get_queryset(self):# 只展示當前用戶的文章return Article.objects.filter(author=self.request.user)class ArticleDetailView(RetrieveAPIView):queryset = Article.objects.all()serializer_class = ArticleSerializerlookup_field = "slug" # 用 slug 查找
這樣 ListAPIView
/ RetrieveAPIView
都是基于 GenericAPIView
實現的。
👉 總結:
GenericAPIView
本身不會直接用,而是作為“可復用的基類”,把 queryset / serializer / 過濾 / 分頁 / 查找對象 的邏輯抽象好,供其他泛型視圖使用。