Это не так неэффективно.Для подключения к сети для определенного эпизода требуется всего три соединения.
Вы можете упростить свою жизнь, если создадите cached_property
для своей модели Episode
:
class Network(models.Model):
name = models.CharField(max_length=255)
# ...
class Episode(models.Model):
season = models.ForeignKey(Season, on_delete=models.CASCADE)
@cached_property
def network(self):
return self.season.series.network
@cached_property
def network_name(self):
return self.season.series.network.name
Это будет дорого использовать, если вы не аннотируете это значение перед доступом к нему, но оно всегда будет работать, даже если вы забудете это сделать.
Хорошая вещь о cached_property
это то, что он может быть переопределен путем установки этого атрибута в экземпляре, что именно то, что делает django, когда мы аннотируем значение:
episodes = Episode.objects.annotate(network_name=F('season__series__network__name'))
for episode in episodes:
print(episode.pk, episode.network_name)
Путем аннотирования имени сети перед доступом к эпизоду, django узнает, что он имеетприсоединиться к этому имени.Вот как выглядит запрос:
SELECT
"main_episode"."id",
"main_episode"."name",
"main_episode"."season_id",
"main_network"."name" AS "network_name"
FROM "main_episode"
INNER JOIN "main_season" ON ("main_episode"."season_id" = "main_season"."id")
INNER JOIN "main_series" ON ("main_season"."series_id" = "main_series"."id")
INNER JOIN "main_network" ON ("main_series"."network_id" = "main_network"."id")
Вы можете видеть, что он присоединился к сети в эпизоде заранее.Так что это один запрос с тремя объединениями.У объединений есть свои затраты, но вам не стоит об этом беспокоиться, пока у вас не возникнут проблемы с производительностью.
Живой пример