继承关系图(文字版+结构图)
🔹 继承关系
APIView
↑
GenericAPIView
↑
+ Mixins (ListModelMixin, CreateModelMixin, etc.)
↑
ViewSet (ModelViewSet, ReadOnlyModelViewSet)
🔹 详细说明
- APIView
- 基础类,封装了
request/response/exception
,类似 Django 的View
。 - 不绑定模型,完全自定义逻辑。
- 基础类,封装了
- GenericAPIView
- 在 APIView 基础上扩展:
queryset
serializer_class
- 提供
get_queryset()
、get_object()
、get_serializer()
等。
- 更适合和模型打交道。
- 在 APIView 基础上扩展:
- Mixin 系列
- 把通用操作做成小模块,可以自由组合:
ListModelMixin
→ 列表CreateModelMixin
→ 新增RetrieveModelMixin
→ 获取单个UpdateModelMixin
→ 更新DestroyModelMixin
→ 删除
- 把通用操作做成小模块,可以自由组合:
- ViewSet / ModelViewSet
- 把 GenericAPIView + Mixins 封装在一起。
- ModelViewSet = 增删改查全家桶。
- 可以和
router
配合自动生成url
。
🔹 总结
- APIView:最基础的类视图,自己实现逻辑。
- GenericAPIView:在 APIView 基础上扩展,和模型绑定,支持 queryset / serializer。
- Mixins:把常用 CRUD 封装成小块。
- ViewSet:= GenericAPIView + Mixins,大多数业务接口首选。
从 APIView 到 ModelViewSet 的完整进化示例
写一个 同一个业务接口(EnterpriseInfo 列表+详情),分别用 APIView → GenericAPIView → GenericAPIView+Mixins → ModelViewSet 来实现。
🟢 版本1:APIView(完全手写)
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from core.enterprise.models import EnterpriseInfo
from core.enterprise.serializers import EnterpriseInfoSerializer
class EnterpriseInfoAPIView(APIView):
def get(self, request, pk=None):
if pk:
obj = EnterpriseInfo.objects.get(pk=pk)
serializer = EnterpriseInfoSerializer(obj)
return Response(serializer.data)
else:
queryset = EnterpriseInfo.objects.all()
serializer = EnterpriseInfoSerializer(queryset, many=True)
return Response(serializer.data)
def post(self, request):
serializer = EnterpriseInfoSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
🟡 版本2:GenericAPIView(提供 queryset
和 serializer_class
)
from rest_framework.generics import GenericAPIView
class EnterpriseInfoGenericAPIView(GenericAPIView):
queryset = EnterpriseInfo.objects.all()
serializer_class = EnterpriseInfoSerializer
def get(self, request, pk=None):
if pk:
obj = self.get_object()
serializer = self.get_serializer(obj)
else:
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
👉 这里不用写 EnterpriseInfo.objects.get
,而是用 get_queryset()
、get_object()
、get_serializer()
。
🟠 版本3:GenericAPIView + Mixins(组合常见操作)
from rest_framework import mixins
class EnterpriseInfoListCreateView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
queryset = EnterpriseInfo.objects.all()
serializer_class = EnterpriseInfoSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class EnterpriseInfoDetailView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
queryset = EnterpriseInfo.objects.all()
serializer_class = EnterpriseInfoSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
🔴 版本4:ModelViewSet(最终形态)
from rest_framework import viewsets
class EnterpriseInfoViewSet(viewsets.ModelViewSet):
queryset = EnterpriseInfo.objects.all()
serializer_class = EnterpriseInfoSerializer
然后 urls.py:
from rest_framework.routers import DefaultRouter
from core.enterprise.views import EnterpriseInfoViewSet
router = DefaultRouter()
router.register(r'enterprise', EnterpriseInfoViewSet)
urlpatterns = router.urls
📌 总结
- APIView:最基础,灵活但代码重复。
- GenericAPIView:提供了
queryset
/serializer_class
,减少重复。 - GenericAPIView + Mixins:常见 CRUD 用 mixins 封装,进一步简化。
- ModelViewSet:全家桶,一行代码搞定,配合 router 自动生成 URL。
对照表,展示 APIView、GenericAPIView、GenericAPIView+Mixins、ModelViewSet 的差异,你背下来就能在面试里直接说。
🔑 Django REST Framework 四种写法对比
写法 | 代码量 | 特点 | 适用场景 | 缺点 |
---|---|---|---|---|
APIView | 代码最多 | 直接继承 APIView ,所有逻辑手写(get/post/put/delete ) | 灵活的自定义接口(如大屏统计、复杂计算) | 代码重复,容易冗余 |
GenericAPIView | 代码少一些 | 提供 queryset 、serializer_class ,内置 get_queryset() 、get_object() 、get_serializer() | 需要标准化 CRUD,但还要定制逻辑 | 依旧要手写 HTTP 方法 |
GenericAPIView + Mixins | 代码更少 | 通过 ListModelMixin / CreateModelMixin / UpdateModelMixin 等组合,直接用 list/create/update/destroy 方法 | 典型的 REST API CRUD | 方法命名受限,灵活性下降 |
ModelViewSet | 最少(几行搞定) | 自带 增删改查,配合 router 自动生成 URL,企业开发最常见 | 常规的表管理、后台 CRUD API | 复杂接口(统计、大屏)不适合 |
📌 示例对比(以 EnterpriseInfo 为例)
写法 | get 列表 | get 单条 | post 创建 |
---|---|---|---|
APIView | 手写 EnterpriseInfo.objects.all() + serializer = Serializer(...) | 手写 get(pk) | 手写校验、保存 |
GenericAPIView | self.get_queryset() | self.get_object() | self.get_serializer(data=...) |
GenericAPIView + Mixins | self.list() | self.retrieve() | self.create() |
ModelViewSet | 自动生成 | 自动生成 | 自动生成 |
✅ 面试套路(推荐你记住这一句话):
“在 DRF 里,开发接口有四层封装:
APIView
最原始,全部手写,灵活但冗余。GenericAPIView
提供了queryset
和serializer_class
,减少重复。- 再结合
Mixins
,就能快速实现 CRUD。ModelViewSet
是最高级别封装,配合router
一行代码搞定增删改查。
通常后台 CRUD 用ModelViewSet
,而大屏统计、非标准接口还是会用APIView
。”