以类似于注释的方式链接Django QuerySet

时间:2018-11-16 15:02:16

标签: django django-models django-orm

我有以下型号:

class Foo(models.Model)
    bar = models.ForeignKey(Bar, on_delete=models.PROTECT)

class Bar(models.Model)
    ...

class Baz(models.Model)
    bar = models.ForeignKey(Bar, on_delete=models.PROTECT)

我想知道是否可以做一些类似于批注的操作来将Baz查询集链接到预先过滤的Foo查询集。像这样:

queryset = Foo.objects.some_filter()
  .annotate(bazs=QuerySet('bar__baz_set.another_filter()'))

请注意,Baz查询集也已过滤,并且Bar可能并不总是具有Baz

这是我希望在模板中实现的:

{% for foo in queryset %}
    ...
    {% for baz in foo.bazs %}
    ...

2 个答案:

答案 0 :(得分:1)

您要寻找的是prefetch_relatedPrefetch

from django.db.models import Prefetch
queryset = Foo.objects.prefetch_related(
    Prefetch(
        'bar__baz_set',
        queryset=Baz.objects.filter(another_filter),
        to_attr='filtered_baz',
    )
)

这是您在模板中使用它的方式:

{% for foo in queryset %}
    ...
    {% for baz in foo.bar.filtered_baz %}
    ...

答案 1 :(得分:0)

这是一个更简单的替代解决方案,但正如其他答案的注释所指出的那样,查询数量有所增加。

class Foo(models.Model):
    bar = models.ForeignKey(Bar, on_delete=models.PROTECT)
    ...
    @cached_property
    def bar_bazs(self):
        return self.bar.get_bazs_by_some_filter()

class Bar(models.Model):
    ...
    def get_bazs_by_some_filter(self):
        return self.baz_set.some_filter()

在模板中:

{% for foo in queryset %}
    ...
    {% for baz in foo.bar_bazs %}
        ...