使用 prefetch_related 仅获取关系的特定条目

NEB*_*NEB 3 django django-models

假设有以下模型

Class A(): pass
Class B():
    i = integer()
    aa = foreignkey('A', related_name = 'fka')
Run Code Online (Sandbox Code Playgroud)

为简单起见,假设以下条目,

A() - a1 -> pk = 1
B() - b1 -> i = 1, aa = a1
B() - b2 -> i = 2, aa = a1
B() - b3 -> i = 3, aa = a1
B() - b4 -> i = 4, aa = a1
B() - b5 -> i = 5, aa = a1
Run Code Online (Sandbox Code Playgroud)

我知道,

foo = A.objects.get(pk = 1).prefetch_related('fka')
Run Code Online (Sandbox Code Playgroud)

会给我条目 b1、b2、b3、b4 和 b5。

但我想知道的是,是否有可能以任何方式更改此查询以仅获取与 A() 关联的 B() 的特定条目。假设我只想预取“B”的条目,“i”为 2(获取 b2,然后跳过 b1、b3、b4 和 b5)。

如果不可能使用预取来做到这一点,那么最好的方法是什么?

注意:get(pk = 1)用于保持解释的简单性,但在那个地方通常会有filter(**conditions).

MBr*_*zle 7

是否需要对 A 对象而不是 B 对象进行查询?如果您反转您进行额外查找的内容,则可以使用select_related()

foo = B.objects.select_related('aa').get(i=2)
Run Code Online (Sandbox Code Playgroud)

这具有减少数据库命中次数的优点。因为prefetch_related()总是进行自己的数据库查找,所以您提出的使用 prefetch_related() 的方案并不比简单地执行更有效:

a = A.objects.get(pk=1)
b = a.fka.get(i=2)
Run Code Online (Sandbox Code Playgroud)

这并不是说它在具有更复杂过滤的场景中不会更有效,而是select_related()使用 SQL 连接,因此只命中数据库一次。也就是说,如果您绝对必须首先查找 A 对象,最好的答案是:升级到 Django 1.7。PrefetchDjango 1.7 中的新命令prefetch_related()允许您指定自定义查询集,从而允许对 进行更复杂的操作,包括过滤:

qs = B.objects.filter(i=2)
foo = A.objects.get(pk = 1).prefetch_related(Prefetch('fka',qs))
Run Code Online (Sandbox Code Playgroud)