Связывание Django QuerySets аналогично аннотациям - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть следующие модели:

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 голосов
/ 19 ноября 2018

Вот альтернативное решение, которое является более простым, но имеет увеличенное количество запросов, как указано в комментариях к другому ответу.

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 %}
        ...
0 голосов
/ 16 ноября 2018

То, что вы ищете, это prefetch_related и Prefetch

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 %}
    ...
...