Django REST Framework 中 ModelViewSet 的接口方法及参数详解,继承的方法和核心类方法,常用查询方法接口

第一部分(ModelViewSet)

一、ModelViewSet 的继承结构

ModelViewSet 继承自以下类:

python 复制代码
ModelViewSet = (
    CreateModelMixin +    # 创建
    RetrieveModelMixin +  # 检索单个
    UpdateModelMixin +    # 更新
    DestroyModelMixin +   # 删除
    ListModelMixin +      # 列表
    GenericViewSet        # 基础视图集
)

二、默认接口方法及参数

以下方法由 ‌mixins‌ 提供,支持 RESTful 标准操作:

方法名 HTTP 方法 参数说明 作用
‌**list(ListModelMixin)**‌ GET self, request, *args, **kwargs 获取资源列表
‌**create** **(CreateModelMixin)**‌ POST self, request, *args, **kwargs 创建新资源
‌**retrieve** **(RetrieveModelMixin)**‌ GET self, request, *args, **kwargs (需 pkslug) 获取单个资源
‌**update** **(UpdateModelMixin)**‌ PUT/PATCH self, request, *args, **kwargs (需 pkslug) 全量/部分更新资源
‌**destroy** **(DestoryModelMixin)**‌ DELETE self, request, *args, **kwargs (需 pkslug) 删除资源
参数统一说明:
  • ‌**request** ‌: Django 请求对象,包含请求数据 (request.data) 和用户信息 (request.user)。
  • ‌***args**‌: URL 中捕获的位置参数(如路径参数)。
  • ==‌****‌==kwargs** : URL 中捕获的关键字参数(如 pk=1)。

三、核心类方法及参数详解

以下方法由 GenericViewSetGenericAPIView 提供,用于控制视图行为:

方法名 参数 返回值 作用
‌**get_queryset()**‌ 无参数,但可通过 self.request 访问请求上下文 QuerySet 返回默认查询集(可覆盖以实现动态过滤)
‌**get_object()**‌ 无参数,从 URL 参数中提取 pkslug 模型实例 获取单个对象,支持 lookup_field 自定义查询字段
‌**get_serializer()**‌ instance=None, data=None, many=False, partial=False, **kwargs 序列化器实例(serializer 初始化序列化器,用于请求数据验证和响应数据生成(对需要更新的数据进行验证并返回验证后的数据)
‌**get_serializer_class()**‌ 无参数,但可通过 self.action 判断当前动作(如 create/update 序列化器类 动态选择序列化器(例如不同动作使用不同序列化器)
‌**perform_create()**‌ serializer (序列化器实例) 无,直接保存对象到数据库 在创建对象前/后执行额外操作(如设置 created_by=request.user
‌**perform_update()**‌ serializer (序列化器实例) 无,直接更新对象到数据库 在更新对象前/后执行额外操作(如记录日志)
‌**perform_destroy()**‌ instance (要删除的模型实例) 无,直接删除对象 在删除对象前/后执行额外操作(如级联删除关联数据)
‌**filter_queryset()**‌ queryset (基础查询集) 过滤后的 QuerySet 应用所有已配置的过滤器(如 DjangoFilterBackend

四、关键参数扩展说明

1. get_object() 的底层参数
  • ‌**lookup_field** ‌: 默认是 'pk',可通过类属性修改为其他字段(如 slug)。
  • ‌**lookup_url_kwarg** ‌: 默认与 lookup_field 相同,指定从 URL 中提取参数的名称。

示例:

python 复制代码
class BookViewSet(ModelViewSet):
    lookup_field = 'isbn'  # 模型字段
    lookup_url_kwarg = 'book_isbn'  # URL 参数名
2. get_serializer() 的参数
  • ‌**instance** ‌: 要更新的模型实例(用于 update 操作)。
  • ‌**data** ‌: 请求数据(request.data)。
  • ‌**partial** ‌: 是否允许部分更新(True 对应 PATCH 请求)。
    • 从请求参数中获取'partial'标识,当值为True时表示PATCH请求(部分更新字段),False时表示PUT请求(完整更新)。通过控制该参数,DRF的序列化器会决定是否进行全字段验证。

五、权限与节流相关方法

方法名 参数 作用
‌**get_permissions()**‌ 返回权限类列表(如 [IsAuthenticated]
‌**get_throttles()**‌ 返回节流类列表(如 [UserRateThrottle]

六、自定义场景示例

1. 动态过滤查询集
python 复制代码
def get_queryset(self):
    # 只返回当前用户创建的书籍
    return Book.objects.filter(created_by=self.request.user)
2. 按动作选择序列化器
python 复制代码
def get_serializer_class(self):
    if self.action == 'list':
        return BookListSerializer
    return BookDetailSerializer
3. 记录操作日志
python 复制代码
def perform_create(self, serializer):
    book = serializer.save(created_by=self.request.user)
    log_action('create', self.request.user, book)

七、完整方法调用流程图

python 复制代码
sequenceDiagram
    participant Client
    participant ViewSet
    Client->>ViewSet: HTTP 请求 (如 GET /books/)
    ViewSet->>ViewSet: determine_action()
    ViewSet->>ViewSet: get_queryset()
    ViewSet->>ViewSet: filter_queryset()
    ViewSet->>ViewSet: get_serializer()
    ViewSet->>ViewSet: perform_动作()
    ViewSet->>Client: 返回 Response

二部分(查询filter)

一、模型关系假设

python 复制代码
# models.py
class PracticeType(models.Model):
    p_type = models.CharField(max_length=50)  # 练习类型字段
    is_active = models.BooleanField(default=True)

class QuestionGroup(models.Model):
    name = models.CharField(max_length=100)
    g_type = models.ForeignKey(PracticeType, on_delete=models.CASCADE)  # 外键关联
    created_at = models.DateTimeField(auto_now_add=True)

class Question(models.Model):
    group = models.ForeignKey(QuestionGroup, on_delete=models.CASCADE, related_name='questions')
    content = models.TextField()
    score = models.IntegerField()

二、查询方法详解(表格)

方法 示例代码 参数说明 作用描述
‌**filter()**‌ QuestionGroup.objects.filter(g_type__p_type='数学') g_type__p_type: 跨模型查询 PracticeType.p_type 字段 筛选 p_type 为 "数学" 的题组
QuestionGroup.objects.filter(created_at__year=2024) created_at__year: 提取日期字段的年份 筛选 2024 年创建的题组
‌**exclude()**‌ QuestionGroup.objects.exclude(g_type__is_active=False) g_type__is_active: 排除关联模型中 is_active=False 的题组 排除关联到非激活练习类型的题组
‌**order_by()**‌ QuestionGroup.objects.order_by('-created_at', 'g_type') -created_at: 按创建时间倒序;g_type: 按外键的默认排序(如 p_type 先按创建时间倒序,再按练习类型排序
‌**values()**‌ QuestionGroup.objects.values('id', 'g_type__p_type') id: 返回题组 ID;g_type__p_type: 返回关联练习类型的 p_type 字段 获取题组 ID 及其关联的练习类型名称
‌**annotate()**‌ QuestionGroup.objects.annotate(total_score=Sum('questions__score')) total_score=Sum('questions__score'): 计算每个题组下所有题目的总分 为每个题组添加总分注解字段 total_score
QuestionGroup.objects.annotate(avg_score=Avg('questions__score')) avg_score=Avg('questions__score'): 计算每个题组下题目的平均分 为每个题组添加平均分注解字段 avg_score

三、参数详细说明

1. ==‌**filter(**‌==kwargs)** - 过滤
  • 参数语法 ‌: 字段__操作符=值(如 created_at__year=2024

  • 跨模型查询 ‌: 使用双下划线 __ 跳转关联模型字段(如 g_type__p_type)。

  • 示例 ‌:

    python 复制代码
    # 查询 p_type 为 "物理" 的题组
    groups = QuestionGroup.objects.filter(g_type__p_type='物理')
    
    # 查询 2023 年之后创建的题组
    groups = QuestionGroup.objects.filter(created_at__year__gte=2023)
2. ==‌**exclude(**‌==kwargs)** - 排除
  • 参数语法 ‌: 同 filter(),但排除满足条件的对象。

  • 示例 ‌:

    python 复制代码
    # 排除关联到非激活练习类型的题组
    groups = QuestionGroup.objects.exclude(g_type__is_active=False)
    
    # 排除 p_type 为 "化学" 的题组
    groups = QuestionGroup.objects.exclude(g_type__p_type='化学')
3. ‌**order_by(*fields)**‌ - 排序
  • 参数语法 ‌: 字段名前加 - 表示倒序(如 -created_at)。

  • 跨模型排序 ‌: 支持按关联模型字段排序(如 g_type__p_type)。

  • 示例 ‌:

    python 复制代码
    # 按练习类型名称升序,再按创建时间倒序
    groups = QuestionGroup.objects.order_by('g_type__p_type', '-created_at')
4. ‌**values(*fields)**‌ - 取字段
  • 参数语法 ‌: 指定要返回的字段或关联字段(如 g_type__p_type)。

  • 返回结果‌: 字典列表(而非模型对象)。

  • 示例 ‌:

    python 复制代码
    # 获取所有题组的 ID、名称及其关联的练习类型名称
    data = QuestionGroup.objects.values('id', 'name', 'g_type__p_type')
5. ‌**annotate(别名=聚合函数)**‌ - 注解
  • 参数语法 ‌: 使用聚合函数(如 Count, Sum, Avg)生成计算字段。

  • 跨模型聚合 ‌: 通过关联模型的 related_name(如 questions)访问子对象。

  • 示例 ‌:

    python 复制代码
    from django.db.models import Count, Sum, Avg
    
    # 统计每个题组的问题数量
    groups = QuestionGroup.objects.annotate(question_count=Count('questions'))
    
    # 计算每个题组的总分和平均分
    groups = QuestionGroup.objects.annotate(
        total_score=Sum('questions__score'),
        avg_score=Avg('questions__score')
    )

四、高级用法

1. 链式调用
python 复制代码
# 查询 2024 年创建的数学题组,按总分降序排列
groups = QuestionGroup.objects.filter(
    g_type__p_type='数学',
    created_at__year=2024
).annotate(
    total_score=Sum('questions__score')
).order_by('-total_score')
2. 跨多级模型查询
python 复制代码
# 查询所有题目分数大于 80 的题组
groups = QuestionGroup.objects.filter(questions__score__gt=80)
3. 空值处理
python 复制代码
# 查询没有关联任何问题的题组
groups = QuestionGroup.objects.filter(questions__isnull=True)

五、性能优化

  • ‌**select_related** ‌: 用于外键或一对一字段的预加载(减少查询次数)。

    python 复制代码
    # 预加载 g_type 关联的 PracticeType 对象
    groups = QuestionGroup.objects.select_related('g_type').filter(g_type__p_type='数学')
  • ‌**prefetch_related** ‌: 用于多对多或一对多字段的预加载。

    python 复制代码
    # 预加载题组下的所有问题
    groups = QuestionGroup.objects.prefetch_related('questions').annotate(total_score=Sum('questions__score'))
相关推荐
问道飞鱼26 分钟前
【Springboot知识】开发属于自己的中间件健康监测HealthIndicate
spring boot·后端·中间件·healthindicate
JM丫28 分钟前
python基础
笔记·python
luckyext2 小时前
Postman用JSON格式数据发送POST请求及注意事项
java·前端·后端·测试工具·c#·json·postman
天才测试猿2 小时前
接口自动化测试用例
自动化测试·软件测试·python·测试工具·测试用例·接口测试·postman
程序视点2 小时前
Redis集群机制及一个Redis架构演进实例
java·redis·后端
程序设计实验室2 小时前
DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级
python·django·djangostarter
鱼樱前端2 小时前
Navicat17基础使用
java·后端
千里码aicood2 小时前
【2025】基于python+django的驾校招生培训管理系统(源码、万字文档、图文修改、调试答疑)
开发语言·python·django
冷琴19962 小时前
基于python+django+vue.js开发的医院门诊管理系统/医疗管理系统源码+运行
vue.js·python·django
黑风风2 小时前
深入理解Spring Boot Starter及如何自定义Starter
java·spring boot·后端