Если вы можете упасть в SQL, вы можете использовать единый запрос (имя_приложения должны префикс все имена таблиц):
select distinct foo.id, bar.id
from baz_foos
join baz on baz_foos.baz_id = baz.id
join foo on baz_foos.foo_id = foo.id
join bar on baz.bar_id = bar.id
baz_foos является многие-ко-многим таблице создает Django.
@ Решение Alasdair возможно/возможно более читаемо (хотя, если вы делаете это по причинам производительности, которые могут быть не самыми важными). Его решение использует ровно два запроса (что вряд ли имеет значение). Единственная проблема, которую я вижу, если у вас есть большое количество Баз объектов, так как генерируемый SQL выглядит следующим образом:
SELECT "foobar_baz"."id", "foobar_baz"."bar_id", "foobar_bar"."id"
FROM "foobar_baz"
INNER JOIN "foobar_bar" ON ("foobar_baz"."bar_id" = "foobar_bar"."id")
SELECT
("foobar_baz_foos"."baz_id") AS "_prefetch_related_val",
"foobar_foo"."id"
FROM "foobar_foo"
INNER JOIN "foobar_baz_foos" ON ("foobar_foo"."id" = "foobar_baz_foos"."foo_id")
WHERE "foobar_baz_foos"."baz_id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
95, 96, 97, 98, 99, 100, 101)
Если у вас есть только несколько бар-х и несколько сотен Foo, я бы сделать:
from django.db import connection
from collections import defaultdict
# foos = {f.id: f for f in Foo.objects.all()}
bars = {b.id: b for b in Bar.objects.all()}
c = connection.cursor()
c.execute(sql) # from above
d = defaultdict(set)
for f_id, b_id in c.fetchall():
d[f_id].add(bars[b_id])
Как бы вы его написали в SQL? – thebjorn
Если бы я знал это, я мог бы перевести его в Django. Я владею базовым SQL, но, увы, не является ниндзя OUTER JOIN. :) –