如何:使用隐式过滤器可预取的相关名称

时间:2019-03-29 15:05:15

标签: django django-models

可以理解,外键可以具有related_name,如下所示:

class Foo(Model):
    ...

class Bar(Model):
    foo = ForeignKey(Foo, related_name='bars')
    hidden = BooleanField()

效果是foo = Foo.objects.first(); foo.bars.all()产生附着到该Bar的任何Foo

但是,我想为所有.bars.all()添加一个默认过滤器,以使标记为“隐藏”的Bar永远不会成为结果查询集的一部分。

这很诱人:

class Foo(Model):
    ...
    @property
    def shown_bars(self):
        return self.bars.filter(hidden=False)

,仅使用foo.shown_bars而不是foo.bars,但我的目标是也使这样的related_name嵌套可预取,即

class Baz(Model):
    foo = ForeignKey(Foo)

# The bars in this queryset *also* automatically excludes bars that are hidden.
# Using `shown_bars` here undoes the prefetch.
Baz.objects.prefetch_related('foo__bars')

因此nested_bars不能在此类表达式中直接使用。

在Django 1.11或2.x中有实现此目的的方法吗?

1 个答案:

答案 0 :(得分:0)

prefetch_related操作中检索到的查询集施加控制的首选方法是使用Prefetch中引入的Django 1.7对象。

您定义所需的查询集:

filtered_bars = Bar.objects.filter(wanted=True)

或者,如果您在filtered上定义了custom manager Bar

filtered_bars = Bar.filtered.all()

然后您在select_related调用中使用查询集:

Baz.objects.prefetch_related(Prefetch(
    'bars',
    queryset=filtered_bars))

人们可能想到的另一种选择是操纵相关对象(这里为Bar)的基础管理器,这将自动影响默认的预取操作。但是,Django docs明确警告不要这样做,因为这样做会阻止Django访问所有对象,这是它必须能够执行的操作。