Django:用不同的非相关模型的计数来注释一个模型的查询,该模型由第一个模型的字段过滤

问题描述 投票:0回答:1

长标题简而言之:我有一个复杂的注释查询要处理。 示例模型:

class FirstModel(models.Model):
    master_tag = models.CharField()
    ... other fields

class SecondModel(models.Model):
    ref_name = models.CharField()

如果该对象的 ref_name 与 FirstModel 对象的 master_tag 相同,我想从 FirstModel 获取所有对象,并从 SecondModel 获取所有对象的计数。

我尝试过的:

我尝试使用 Subquery 和 OuterRef 进行注释,但无法使其正常工作,因为不断出现错误。

from django.db.models import OuterRef, Subquery, Count

sub_query = Subquery(
    SecondModel.objects.filter(ref_name=OuterRef("master_tag")).values_list("pk", flat=True)
)
FirstModel.objects.annotate(sm_count=Count(sub_query))

这给了我错误:“django.db.utils.ProgrammingError:用作表达式的子查询返回不止一行” 我尝试了很多其他方法,其中之一是将“.count()”放在子查询的末尾,但这会导致另一个错误,因为 count 试图急切地评估查询并由于 OuterRef 而失败。

那么有没有一种方法可以使用 count 注释来获取这样的查询?我在编写上述查询时犯过任何愚蠢的错误吗?

python django annotations
1个回答
0
投票

我已经尝试使用 OuterRef 和 Subquery 解决这个问题有一段时间了,但我意识到主要问题是 Subquery 表达式被设计为返回单个值,而在这种情况下您需要返回多个值。

Django 似乎不直接支持使用基于字段比较的不相关模型实例的计数来注释查询集。

我只使用 Django 和 RawSQL 的组合,在没有子查询的情况下实现了你想要的:

from django.db.models.expressions import RawSQL

# Annotate FirstModel queryset with RawSQL
qs = FirstModel.objects.annotate(
    sm_count=RawSQL(
        """
        SELECT COUNT(*) FROM yourapp_secondmodel 
        WHERE yourapp_secondmodel.ref_name = yourapp_firstmodel.master_tag
        """,
        []
    )
)

# Check the sm_count values
qs.values('master_tag','sm_count').order_by('-sm_count')

另一种选择是迭代 FirstModel 的所有实例,计算 ref_name 出现的次数,但这效率很低,仅在小数据集中可行......

结论:如果这些模型之间存在外键,这会容易得多。

如果有人能够使其与子查询一起工作,我很高兴被证明是错误的,但与此同时,RawSQL 可以为您解决问题,并且它仍然会返回查询集。

© www.soinside.com 2019 - 2024. All rights reserved.