【问题标题】:How do I annotate onto a select_related model?如何在 select_related 模型上进行注释?
【发布时间】:2019-05-04 17:08:01
【问题描述】:

我为查询集中的每个对象选择了一个相关对象。如何为每个值注释一个计算值?

型号:

class School(models.Model):
    name = models.CharField(max_length=255)


class Teacher(models.Model):
    name = models.CharField(max_length=255)
    school = models.ForeignKey(School)


class Student(Entity):
    name = models.CharField(max_length=255)
    school = models.ForeignKey(School)

我想获取所有老师和每个老师的学校,以及该学校的学生人数。

这是我尝试过的:

teachers = Teacher.objects.select_related('school').annotate(student_count=Count('school__student'))

但我可以看出这是错误的,因为学生人数需要每所学校

我希望之后能够用我的查询集做这样的事情:

for teacher in teachers:
  print(teacher.name, teacher.school.name, teacher.school.student_count)

【问题讨论】:

  • 您可以使用teacher.student_count 获取它。您总是在您查询的模型上进行注释。由于在您的建模中,一位老师属于单一学校,因此结果没有什么不同。

标签: django orm


【解决方案1】:

但我可以看出这是错误的,因为学生人数需要每所学校

好吧,您将计算属于该教师所属学校的学生,因此这在语义上是有效的。然而,注释将放在查询集中的对象上,因此是教师,因此您可以使用以下方法获取学生人数:

for teacher in teachers:
  print(teacher.name, teacher.school.name, teacher.student_count)

由于多个教师可以属于同一所学校,以这种方式注释可能不是最好的主意,因为如果不优化,这意味着您将计算该学校的学生人数每个老师。尽管从语义上讲这不会改变任何东西,但查询可能需要相当长的时间。

您可以决定为给定的school 使用.prefetch_related(..),并在Prefetch object [Django-doc] 中注释该查询集,这将导致额外的查询,但成本更低。例如:

from django.db.models import Prefetch, Count

teachers = Teacher.objects.prefetch_related(
    Prefetch(
        'school',
        queryset=School.objects.annotate(student_count=Count('student'))
    )
)

那么你确实可以查询:

for teacher in teachers:
  print(teacher.name, teacher.school.name, teacher.school.student_count)

【讨论】:

  • 是的,这就是它的核心。谢谢你。虽然学校可以是select_related,所以他们加载了一个连接,计数应该在prefetch_related查询集上获取,所以就像你说的,如果有很多老师属于少数学校(很可能在现实中)计数只做几次而不是多次。所以你不能select_related学校本身,而是prefetch_related计算出来的school.student_count?我猜它会如何将两者缝合在一起:(。
  • @PaulMitchell-Gears:通常最后一个只会导致两个查询 iirc。然后是 Django 将学校一起“静态化”给老师。我认为两个查询并不那么昂贵,特别是因为我们使查询可能比我们希望使用.select_related(..) 变体便宜很多。
猜你喜欢
  • 2020-12-15
  • 2019-07-21
  • 1970-01-01
  • 1970-01-01
  • 2012-03-20
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 2019-03-16
相关资源
最近更新 更多