Возможно ли здесь избежать n+1 запроса в django? Если да, то как?
У меня есть эти модели
class Thing1(MyModel):
thing2 = models.OneToOneField(
Thing2, on_delete=models.PROTECT, related_name="super_pack"
)
some_id = models.IntegerField()
class Thing2(MyModel):
name = models.CharField(max_length=50, primary_key=True)
class Thing3(MyModel):
name = models.CharField(max_length=255)
thing2 = models.ForeignKey(
Thing2,
related_name="thing3s",
)
class Thing4(MyModel):
root_thing3 = models.OneToOneField(
Thing3, on_delete=models.PROTECT, related_name="my_related_name"
)
member_item_thing3s = models.ManyToManyField(
Thing3,
through="unimportant",
related_name="important_related_name",
)
is_default = models.BooleanField(default=False)
Я работаю с сериализатором Django. У меня уже определен queryset с предварительной выборкой.
В существующем виде, следующее выполняется:
all_thing1s: QuerySet[Thing1]
for thing1 in all_thing1s:
first_thing3 = Thing1.thing2.thing3s.all()[0]
(далее предполагается, что мы находимся в теле цикла)
что не идеально, если всегда есть 1 thing3
схема не должна позволять много, но я не могу изменить схему в настоящее время.)
На данный момент я считаю, что возможность дальнейшей предварительной выборки была нарушена, поскольку мы вернули Thing3 (first_thing3
) и больше не имеем набора запросов для работы В начале этого я думал, что Django магически использует предыдущие префетчи, я не понимал, что фильтры и т.д., которые вы хотите использовать префетчи, должны быть привязаны к префетчам.
Но теперь я хочу сделать:
thing4 = first_thing3.important_related_name.all()[0]
return thing4.root_thing3
(примечание: first_thing3
и root_thing3
имеют один и тот же тип, но не являются одним и тем же. И да, опять то же глупое предположение, что существует единственное thing4
, связанное с first_thing3
)
Но согласно жирному тексту, я считаю, что предварительная выборка на кверисете представления невозможна.
Я подумала, что, возможно, ты мог бы быть таким
first_thing3 = Thing1.thing2.thing3s.all()[0]
query_set = Thing1.thing2.thing3s.filter(id=first_thing.id)
query_set.important_related_name[0]
...
Но нет, потому что добавление фильтра должно быть учтено в исходной предварительной выборке, что невозможно, а последующая important_related_name
имеет смысл только в том случае, если она все равно относится к одному элементу.
Итак, это было около 8 часов открытий для меня. Думаю, я определил, что здесь невозможна предварительная выборка с помощью Django и что n+1 неизбежно.
Может ли кверисет быть агрегатом?
Я хочу подтвердить, что избежать n+1 невозможно (используя встроенную функциональность Django).