介绍 Django REST framework (DRF) 中的 viewsets.ModelViewSet
,包括其作用、继承关系、默认提供的功能、常见使用方式、适用场景,以及如何在项目架构中正确组织。
1. 什么是 ModelViewSet
在 Django REST framework (DRF) 中,viewsets.ModelViewSet
是一个视图集 (ViewSet),它自动整合了常见的 CRUD 操作(增删改查),基于指定的 模型 (Model) 和 序列化器 (Serializer),大幅减少了样板代码。
也就是说,如果你要为某个模型提供完整的 RESTful API(列表、详情、创建、修改、删除),只需要写一个 ModelViewSet
,再通过 router
自动生成 URL,就能完成。
2. 继承关系
ModelViewSet
的继承关系如下:
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
拆解:
Mixins
CreateModelMixin
→ 提供create()
方法 →POST /resources/
RetrieveModelMixin
→ 提供retrieve()
方法 →GET /resources/{pk}/
UpdateModelMixin
→ 提供update()
/partial_update()
方法 →PUT/PATCH /resources/{pk}/
DestroyModelMixin
→ 提供destroy()
方法 →DELETE /resources/{pk}/
ListModelMixin
→ 提供list()
方法 →GET /resources/
GenericViewSet
- 提供了
get_queryset()
、get_serializer_class()
等通用功能 - 结合上面的 Mixins,最终形成一个完整的 CRUD API。
- 提供了
3. 默认提供的 API 行为
如果你写了一个 ModelViewSet
,并注册到 router
中,你自动获得如下 RESTful API:
方法 | URL | 动作 | Mixin |
---|---|---|---|
GET | /objects/ |
列表查询 | ListModelMixin |
POST | /objects/ |
创建数据 | CreateModelMixin |
GET | /objects/{pk}/ |
获取单条数据 | RetrieveModelMixin |
PUT | /objects/{pk}/ |
更新整条数据 | UpdateModelMixin |
PATCH | /objects/{pk}/ |
部分更新数据 | UpdateModelMixin |
DELETE | /objects/{pk}/ |
删除数据 | DestroyModelMixin |
4. 使用示例
示例模型
# models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
published_date = models.DateField()
price = models.DecimalField(max_digits=6, decimal_places=2)
示例序列化器
# serializers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
示例 ViewSet
# views.py
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
路由注册
# urls.py
from rest_framework.routers import DefaultRouter
from .views import BookViewSet
router = DefaultRouter()
router.register(r'books', BookViewSet)
urlpatterns = router.urls
这样,你就自动获得了 /books/
和 /books/{id}/
的完整 CRUD API。
BookViewSet
API 方法总览表
方法名 | HTTP 方法 | URL 格式 | 来源 | 作用说明 |
---|---|---|---|---|
list(self, request) |
GET | /books/ |
ListModelMixin | 获取所有书籍的列表(可分页、可过滤、可排序) |
create(self, request) |
POST | /books/ |
CreateModelMixin | 创建一本新书,并保存到数据库 |
retrieve(self, request, pk=None) |
GET | /books/{id}/ |
RetrieveModelMixin | 获取单本书籍的详细信息 |
update(self, request, pk=None) |
PUT | /books/{id}/ |
UpdateModelMixin | 更新整条书籍记录(所有字段都要传) |
partial_update(self, request, pk=None) |
PATCH | /books/{id}/ |
UpdateModelMixin | 局部更新书籍(只更新提交的字段) |
destroy(self, request, pk=None) |
DELETE | /books/{id}/ |
DestroyModelMixin | 删除一本书籍 |
recent(self, request) |
GET | /books/recent/ |
自定义 @action | 获取最近出版的 5 本书 |
说明
默认方法 来自 DRF 的
ModelViewSet
(继承了一组 mixin)。自定义方法 使用
@action
装饰器,可以定义新的 API 路径。detail=False
→ 不需要主键(例如/books/recent/
)detail=True
→ 需要主键(例如/books/{id}/publish/
)
5. 常见扩展与自定义
5.1 权限控制
from rest_framework.permissions import IsAuthenticated
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = [IsAuthenticated]
5.2 过滤与搜索
from rest_framework import filters
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ['title', 'author']
ordering_fields = ['published_date', 'price']
5.3 自定义方法(额外接口)
from rest_framework.decorators import action
from rest_framework.response import Response
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
@action(detail=False, methods=['get'])
def recent(self, request):
books = self.queryset.order_by('-published_date')[:5]
serializer = self.get_serializer(books, many=True)
return Response(serializer.data)
现在 /books/recent/
就是一个新接口。
6. 适用场景
✅ 适合:
- 快速开发 标准化的 CRUD 接口
- 数据表和 API 一一对应的场景
- 中小型项目、原型开发
⚠️ 不太适合:
- 大型系统中业务逻辑复杂、接口与模型关系不直接对应的场景
- 接口过于定制化,不完全遵循 RESTful CRUD 的场景
在复杂项目中,可能需要继承 GenericViewSet
+ 部分 Mixins,而不是用 ModelViewSet
一把梭。
7. 最佳实践
小项目:直接用
ModelViewSet
+router
,快速开发中大型项目:
ModelViewSet
用于简单、标准 CRUD- 自定义
GenericViewSet
/ APIView 用于复杂业务 - 在
views/
目录下按业务模块拆分,而不是所有 ViewSet 放在一个文件里 - 配合 序列化器分层(输入 / 输出不同 Serializer)提高可维护性