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

如何用Django ORM获取所有外键关联数据(无需循环)

Django ORM 批量查询关联数据(无ORM循环)

我来帮你搞定这个问题,不需要在ORM层面做循环就能拿到你想要的结构化结果,下面一步步来梳理:

你的现有模型与需求

模型定义

class A(models.Model):
    name = models.CharField(max_length=1000, unique=True)

class B(models.Model):
    name = models.CharField(max_length=1000, unique=True)
    a = models.ForeignKey(A, on_delete=models.PROTECT, related_name="a")

期望结果格式

[{
    "name":"a",
    "a":[{ "name":"a1"}, { "name":"b1"}, { "name":"c1"}]
}, {
    "name":"b",
    "b":[{ "name":"a2"}]
}]

示例数据表数据

表A

idname
1a
2b

表B

idnamea
1a11
2b11
3c11
4a22

你已经能实现单条A记录的关联查询:

a_ob = A.objects.get(id=1)
b_ob = a_ob.a.all()

现在需要批量获取所有A记录的对应格式结果,且避免ORM循环。


三种可行解决方案

这个方法用prefetch_related一次性加载所有A和关联的B数据(仅2次SQL查询,避免N+1问题),然后用Python列表推导来构造格式——这里的遍历是Python层面的,不是ORM循环,性能很好:

from django.db.models import Prefetch

# 提前预加载所有A及其关联的B数据,只取name字段
a_queryset = A.objects.prefetch_related(
    Prefetch('a', queryset=B.objects.only('name'))
).all()

# 构造目标格式
result = [
    {
        'name': a.name,
        a.name: [{'name': b.name} for b in a.a]
    }
    for a in a_queryset
]

方法二:DRF序列化器(优雅适配API场景)

如果你的项目用了Django REST Framework,用序列化器来处理会更优雅,可读性和可维护性都更强:

from rest_framework import serializers

# 先定义B的序列化器,只返回name字段
class BSerializer(serializers.ModelSerializer):
    class Meta:
        model = B
        fields = ('name',)

# 定义A的序列化器,动态生成以A.name为键的关联字段
class ASerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        # 先获取基础的name字段数据
        data = super().to_representation(instance)
        # 序列化关联的B数据
        b_serialized = BSerializer(instance.a.all(), many=True).data
        # 添加以A的name为键的字段
        data[instance.name] = b_serialized
        return data

    class Meta:
        model = A
        fields = ('name',)

# 优化查询,预加载关联数据避免N+1
a_queryset = A.objects.prefetch_related('a').all()
# 序列化所有A对象
serializer = ASerializer(a_queryset, many=True)
result = serializer.data

方法三:PostgreSQL专属的JSON聚合(数据库层面完成)

如果你的数据库是PostgreSQL,可以直接用Django的聚合函数在数据库层面生成结构化数据,性能最优:

from django.db.models import Func, Value
from django.contrib.postgres.aggregates import JSONAgg

# 自定义函数,生成{"name": xxx}格式的JSON对象
class BuildNameObject(Func):
    function = 'json_build_object'
    template = "%(function)s('name', %(expressions)s)"

# 聚合查询,直接在数据库层面生成关联的B数据数组
a_aggregated = A.objects.annotate(
    b_list=JSONAgg(BuildNameObject('a__name'))
).values('name', 'b_list')

# 转换为目标格式
result = [
    {'name': item['name'], item['name']: item['b_list']}
    for item in a_aggregated
]

内容的提问来源于stack exchange,提问作者Shyamala Gopalakrishnan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:20:48