Оптимизация аналогичных кверисетов в Django
Я создаю сайт с фильмографией. Однако мне трудно оптимизировать набор запросов в детальном просмотре.
class Actor(model.Models):
id = models.IntegerField()
name = models.CharField()
class Movie(model.Models):
id = models.IntegerField()
movie_title = models.CharField()
actor = models.ManyToManyField(Actor, related_name='relations')
class ActorView(DetailView):
model = Actor
context_object_name = 'actor'
template_name = 'actor.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['movies'] = self.object.relations.all()
return context
<div>
{{ actor.name }}
{% for movie in movies %}
{{ movie.movie_title }}
{% for actor_info in movie.actor.all %}
{{ actor.name }}
{% endfor %}
{% endfor %}
</div>
Я проверил sql-тап в отладочной консоли django.
{% for actor_info in movie.actor.all %}
{{ actor.name }}
{% endfor %}
В приведенном выше коде похожие запросы выполняются многократно. И время соединения с данными и выполнения запроса также очень медленное. Как я могу оптимизировать эту часть в представлении или модели?
Вы можете ускорить этот процесс, используя prefetch_related
Так что в вашем представлении измените эту строку на
context['movies'] = self.object.relations.all()
to
context['movies'] = self.object.relations.all().prefetch_related("actor")
В Django, select_related и prefetch_related предназначены для того, чтобы остановить поток запросов к базе данных, вызванных обращением к связанным объектам, как упоминалось
Итак, для отношений ForeignKey
и OneToOneField
можно использовать select_related
, а для отношений ManyToManyField
можно использовать prefetch_related
, которые.
Django говорит
Prefetch related возвращает QuerySet, который автоматически извлекает, в одном пакете, связанные объекты для каждого из указанных поисков.
Это имеет сходное назначение с select_related, в том смысле, что оба предназначены для прекращения потока запросов к базе данных, вызванного обращением к связанным объектам, но стратегия совершенно другая.
select_related работает путем создания SQL-соединения и включения полей связанного объекта в оператор SELECT. По этой причине select_related получает связанные объекты в одном запросе к базе данных. Однако, чтобы избежать гораздо большего набора результатов, который может возникнуть в результате объединения через "многие" отношения, select_related ограничен однозначными отношениями - внешним ключом и один-к-одному.
.
class ActorView(DetailView):
model = Actor
context_object_name = 'actor'
template_name = 'actor.html'
# Overide the get_object method and set prefetch_related
def get_object(self, queryset):
return super().get_object(queryset).prefetch_related("movies")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['movies'] = self.get_object().relations.all()
return context