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

如何在Django查询中为User模型注解关联Company属性

解决Django百万级用户关联Company查询的性能问题

你现在的写法是典型的N+1查询问题——每序列化一个User就发起一次Company查询,百万级数据下必然性能暴跌。直接在查询阶段用annotate结合Subquery和OuterRef,就能把Company的字段注解到User对象上,全程只走一次SQL查询。

具体实现步骤:

  1. 导入必要的查询工具
from django.db.models import Subquery, OuterRef
  1. 构造子查询获取对应Company的字段
    先定义子查询,筛选当前User对应的Company(这里按id取第一条,和你原来的first()逻辑完全一致):
# 子查询:匹配当前User的id,取第一条Company数据
company_subquery = Company.objects.filter(
    user_id=OuterRef('id')
).order_by('id')[:1]
  1. 查询User时注解Company字段
    在查询User集合时,把Company的name和size直接注解到User对象上:
users = User.objects.annotate(
    company_name=Subquery(company_subquery.values('name')),
    company_size=Subquery(company_subquery.values('size'))
)
  1. 修改序列化器直接映射注解字段
    不用再重写to_representation,直接在序列化器里新增字段,映射注解的属性:
class UserSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    email = serializers.EmailField(read_only=True)
    # 映射注解的字段,允许为null(无对应Company时返回空)
    name = serializers.CharField(source='company_name', read_only=True, allow_null=True)
    size = serializers.IntegerField(source='company_size', read_only=True, allow_null=True)

额外优化建议:

如果你的业务逻辑里一个User对应唯一Company,建议直接修改Company模型,把user_id改成外键关联:

class Company(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True, related_name='company')
    name = models.CharField(max_length=100)
    size = models.IntegerField(default=1)

之后可以用select_related直接关联查询,写法更简洁:

users = User.objects.select_related('company').all()

序列化器里也能直接嵌套Company序列化器,或者直接取company.name、company.size。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:25:17