You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django类视图中查询通过ModelC关联的ModelA与ModelB数据

问题分析与解决方案

原代码存在的问题

  1. Django QuerySet 没有 join 方法,关联查询需通过 select_related/prefetch_related 或跨模型过滤、annotate 实现
  2. 模型引用错误:代码中 Oas_Spend 应为 ModelB 的笔误
  3. 过滤条件语法错误:filter('band__brand_id') 不符合 Django 过滤规则,需传入关键字参数
  4. F表达式使用错误:ModelC 不存在 brand_id 字段,关联字段应为 band__id
  5. 冗余重写 get 方法:ListAPIView 已内置分页、序列化逻辑,无需重复实现

修正后的实现

1. 调整 QuerySet 逻辑

根据需求,我们从 ModelA 出发,关联 ModelC(乐队信息)和 ModelB(支出数据),通过 annotate 聚合乐队总支出,再用 values 提取所需字段:

from django.db.models import Sum, F
from rest_framework.generics import ListAPIView
from .models import ModelA, ModelB, ModelC
from .serializers import MySerializer
from .pagination import DataPagination

class MyView(ListAPIView):
    serializer_class = MySerializer
    pagination_class = DataPagination  # 直接指定分页类

    def get_queryset(self):
        # 关联乐队信息,聚合该乐队的总支出,提取所需字段
        queryset = ModelA.objects.select_related('band').annotate(
            spending=Sum('band__bandspends__spending')
        ).values(
            'band_id',
            band_label=F('band__label'),
            'spending',
            'id',
            'date'
        )
        return queryset

如果需要获取每个支出记录对应关联的乐队活动数据(而非总支出),可改用以下 QuerySet:

def get_queryset(self):
    queryset = ModelA.objects.select_related('band').filter(
        band__bandspends__isnull=False
    ).values(
        'band_id',
        band_label=F('band__label'),
        spending=F('band__bandspends__spending'),
        'id',
        'date'
    )
    return queryset

2. 序列化器定义

对应返回字段,编写序列化器:

from rest_framework import serializers

class MySerializer(serializers.Serializer):
    band_id = serializers.IntegerField()
    band_label = serializers.CharField()
    spending = serializers.FloatField()
    id = serializers.IntegerField()
    date = serializers.DateTimeField()

3. 说明

  • select_related('band'):提前加载关联的 ModelC 数据,避免N+1查询
  • annotate(Sum('band__bandspends__spending')):通过反向关联(ModelC 的 bandspends 对应 ModelB 集合)计算乐队总支出
  • values 中的 F 表达式:将 ModelC 的 label 字段重命名为 band_label,匹配期望的JSON格式

最终返回格式

执行后将返回符合需求的JSON结构:

[
    {
        "band_id": 100,
        "band_label": "MLTR",
        "spending": 900.000,
        "id": 2212121,
        "date": "2018-02-01T00:00:00Z"
    }
]

内容的提问来源于stack exchange,提问作者85nd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:32:41