Я создаю приложение Django, которое отслеживает награды, которые получает человек. Ниже приводится упрощенное представление двух моделей, которые у меня есть:Уменьшение количества запросов в Django
class AwardHolder(models.Model):
name = models.CharField()
def get_total_awards(self):
entries = self.award_set.all()
calc = entries.aggregate(sum=Sum('units_awarded'))
return calc.get('sum') or 0
class Award(models.Model)
date_awarded = models.DateField()
units_awarded = models.IntegerField()
award_holder = models.ForeignKey(AwardHolder)
Я создал сводную страницу для владельца награды, где он может увидеть его полные награды. Я использую функцию get_total_awards
выше. Все работает хорошо, но затем я создал обзорную страницу, чтобы отобразить общие награды на каждого обладателя премии. Я использую функцию ниже, чтобы получить общее количество наград за обладателя премии:
def get_all_awards():
qs = AwardHolder.objects.all()
awards = []
for ah in qs:
awards.append((ah, ah.get_total_awards())
return awards
Это порождает большое количество запросов, так как он попадает в дб каждом проходе цикла. Есть ли способ, которым я могу использовать prefetch_related
или какой-нибудь другой трюк db, чтобы уменьшить количество запросов db, не переписывая get_all_awards()
?
Фактический код, который я использую, имеет намного больше полей и более сложный, чем этот пример. Есть около 10 функций, подобных get_all_awards()
, поэтому переписывать его будет совсем немного. Однако для 100 обладателей премий мой код генерировал колоссальные 18000 запросов, поэтому я знаю, что мне это нужно как-то исправить.
Я думаю, что это работа для аннотирования, а не совокупности. Что-то вроде 'AwardHolder.objects.annotate (Count ('award__units_awarded'))' –
Я надеялся избежать этого, так как мне пришлось бы переделать много функций. Я полагаю, что функция get_total_awards внутри AwardHolder все равно будет применяться, если мне нужно только количество наград для одного обладателя премии? – Johan
Для одного обладателя премии эта функция идеальна, если у вас не может быть меньше одного запроса: P Для больших чисел лучше делать все в одном запросе, а не в цикле, и выполнять несколько запросов, но вам нужно будет проверить, annotate' действительно делает то, что я думаю, что он делает –