Django REST框架:ModelViewSet全面解析

介绍 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 的继承关系如下:

python 复制代码
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. 使用示例

示例模型

python 复制代码
# 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)

示例序列化器

python 复制代码
# serializers.py
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

示例 ViewSet

python 复制代码
# 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

路由注册

python 复制代码
# 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 本书

说明

  1. 默认方法 来自 DRF 的 ModelViewSet(继承了一组 mixin)。

  2. 自定义方法 使用 @action 装饰器,可以定义新的 API 路径。

    • detail=False → 不需要主键(例如 /books/recent/
    • detail=True → 需要主键(例如 /books/{id}/publish/

5. 常见扩展与自定义

5.1 权限控制

python 复制代码
from rest_framework.permissions import IsAuthenticated

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAuthenticated]

5.2 过滤与搜索

python 复制代码
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 自定义方法(额外接口)

python 复制代码
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)提高可维护性
相关推荐
倔强的石头_1 分钟前
场景化落地指南——金仓时序数据库在关键行业的应用实践
数据库
知乎的哥廷根数学学派1 分钟前
基于自适应多尺度小波核编码与注意力增强的脉冲神经网络机械故障诊断(Pytorch)
人工智能·pytorch·python·深度学习·神经网络·机器学习
SelectDB20 分钟前
驾驭 CPU 与编译器:Apache Doris 实现极致性能的底层逻辑
运维·数据库·apache
zbguolei30 分钟前
MySQL根据身份证号码计算出生日期和年龄
数据库·mysql
cnxy1881 小时前
Python爬虫进阶:反爬虫策略与Selenium自动化完整指南
爬虫·python·selenium
马克学长1 小时前
SSM校园图书借阅服务系统jd2z8(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·图书管理系统·ssm 框架·ssm 校园图书借阅系统
软件派1 小时前
高斯数据库使用心得——从性能优化到行业实践的深度解析
数据库·oracle
用户8356290780512 小时前
Python 实现 Excel 条件格式自动化
后端·python
Chan163 小时前
场景题:CPU 100% 问题怎么排查?
java·数据库·redis·后端·spring
深蓝电商API3 小时前
Scrapy管道Pipeline深度解析:多方式数据持久化
爬虫·python·scrapy