如何在Django查询中引用其他关联记录的数据?
Django Foo模型baz方法的正确实现方案
问题背景
已知F()可调用当前记录的数据,需在Django的Foo模型baz方法中完成以下逻辑:
- 计算当前记录的
my_cumulative_field与自身foo_set中**小于该值的最大my_cumulative_field**的差值 - 用该差值乘以
foo_set中每条记录的weight字段后,聚合求和
尝试过两种方法但未得到预期结果:
- 通过
filter筛选后取last()的方式计算差值 - 尝试用
F('bar').my_cumulative_field引用关联字段
正确实现思路
直接用Python代码(如last())查询数据库会导致无法与ORM的F()表达式联动,必须用纯ORM查询的方式实现差值计算:
- 用
Subquery和OuterRef获取每个关联记录对应的最大my_cumulative_field(小于当前记录的值) - 在
annotate中直接计算差值,再乘以weight - 最后聚合求和
完整代码实现
from django.db.models import F, Sum, Subquery, OuterRef class Foo(models.Model): bar = models.ForeignKey('self', on_delete=models.CASCADE) my_cumulative_field = models.IntegerField('my_cumulative_field') weight = models.FloatField('weight') def baz(self): # 子查询:获取foo_set中小于当前记录my_cumulative_field的最大值 max_prev_subquery = Foo.objects.filter( bar=self, my_cumulative_field__lt=OuterRef('my_cumulative_field') ).order_by('-my_cumulative_field').values('my_cumulative_field')[:1] my_value = self.foo_set.annotate( # 计算差值:当前记录值减去子查询结果,无匹配则用0代替 difference=F('my_cumulative_field') - Subquery(max_prev_subquery, output_field=models.IntegerField()) ).annotate( # 差值乘以weight字段 my_annotation=F('difference') * F('weight') ).aggregate( my_aggregation=Sum('my_annotation', output_field=models.FloatField()) ).get('my_aggregation', 0.0) return my_value
关键说明
Subquery+OuterRef实现关联子查询,确保所有计算在数据库层面完成,能和F()表达式联动- 子查询通过
order_by('-my_cumulative_field')[:1]精准获取小于当前值的最大记录 - 若
foo_set中无符合条件的记录,Subquery返回None,此时差值等于当前记录的my_cumulative_field(数据库中None会被视为0) - 全程用ORM表达式实现,避免Python代码与数据库查询分离导致的逻辑错误
内容的提问来源于stack exchange,提问作者BKO
相关产品推荐
相关产品推荐

