如何在Django查询中为User模型注解关联Company属性
解决Django百万级用户关联Company查询的性能问题
你现在的写法是典型的N+1查询问题——每序列化一个User就发起一次Company查询,百万级数据下必然性能暴跌。直接在查询阶段用annotate结合Subquery和OuterRef,就能把Company的字段注解到User对象上,全程只走一次SQL查询。
具体实现步骤:
- 导入必要的查询工具
from django.db.models import Subquery, OuterRef
- 构造子查询获取对应Company的字段
先定义子查询,筛选当前User对应的Company(这里按id取第一条,和你原来的first()逻辑完全一致):
# 子查询:匹配当前User的id,取第一条Company数据 company_subquery = Company.objects.filter( user_id=OuterRef('id') ).order_by('id')[: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')) )
- 修改序列化器直接映射注解字段
不用再重写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
相关产品推荐
相关产品推荐

