【问题标题】:Django Nested ManyToManyField objects count queryDjango 嵌套 ManyToManyField 对象计数查询
【发布时间】:2020-04-25 02:35:00
【问题描述】:
  • 我们以Project为主要模型,其中包含2个M2M关系字段。
class First(models.Model):
   first_results_M2M = models.ManyToManyField(First_Results)

class Second(models.Model):
   second_results_M2M = models.ManyToManyField(Second_Results)

class Project(models.Model):
    project_first_M2M = models.ManyToManyField(First)
    project_second_M2M = models.ManyToManyField(Second)
  • 我正在尝试计算每个Project 对象内所有project_first_M2M 对象中存在的所有first_results_M2M 对象。

  • 下面是计算first_results_M2M 的所有对象的示例,用于Project 对象1。

total_first_all = First_Results.objects.filter(first__project__id=1).count()

  • 我想在模板中呈现total_first_alltotal_second_all 的总数。
Project_Query = Project.objects.all()
for each_proj in Project_Query:
  print(each_proj.total_first_all) ## should print the count the `first_resuls_M2M` for each project obj.
  • 请让我知道如何以更有效/更快的方式实现它,除了注释。

annotate.total_first_all=Count('project_first_M2M__first_results_M2M')

【问题讨论】:

  • 你可以.annotate(...)
  • 我第一次尝试使用注释然后我意识到在多个字段上使用注释会使查询非常慢。 `stackoverflow.com/questions/59622503/…
  • 如果您在多个 不同 连接上进行注释,则会生成大量 JOIN(在该示例中总共有四个),这确实会“炸毁”,解决方案表.但是执行这样的查询当然没有任何意义。如果您在此处执行单个嵌套 JOIN,则它会导致两个 JOIN,并且您会考虑所有产生的记录。
  • 有没有办法从 django ORM 执行单个嵌套 JOIN 或必须使用原始查询来执行?
  • 你使用Subquery

标签: django django-models django-rest-framework django-forms django-templates


【解决方案1】:

.annotate(..) [Django-doc]你的查询集,比如:

from django.db.models import Count

project_query = Project.objects.annotate(
    total_first_all=Count('project_first_M2M__first_results_M2M')
)

for project in project_query:
    print(project.total_first_all)

不会查询每个 Project 对象,但会计算所有 Projects 在“批量”中的计数.

对于多个,可以利用子查询减少JOIN的嵌套数量:

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

project_query = Project.objects.annotate(
    total_first_all=Subquery(
        First_Results.objects.filter(first__project=OuterRef('pk')).values('first__project').values(cnt=Count('*')).order_by('first__project')
    ),
    total_second_all=Subquery(
        Second_Results.objects.filter(second__project=OuterRef('pk')).values('second__project').values(cnt=Count('*')).order_by('second__project')
    )
)

【讨论】:

  • django.db.utils.ProgrammingError: subquery must return only one column 过度迭代 project_query 对象,我正在使用 Postgresql DB。
  • @ArbazzHussain:如果我们将.values(..)Count(..) 表达式一起使用会怎样?
  • 很抱歉它抛出了AttributeError, AttributeError: 'Count' object has no attribute 'split', pastebin.com/raw/HDiHzC1N
  • stackoverflow.com/a/47371514/10372434 对我来说似乎是一个很好的解决方案,你觉得呢?
  • @ArbazzHussain:抱歉,还是有错误。
猜你喜欢
  • 2020-04-22
  • 2022-01-01
  • 2020-03-19
  • 1970-01-01
  • 2021-10-02
  • 2013-06-03
  • 2021-01-24
  • 1970-01-01
相关资源
最近更新 更多