Я столкнулся с серьезной проблемой производительности в связи с django-mptt. Вот мой случай:
- У меня класс викторины
- У меня есть класс вопросов с FK для викторины и FK для класса Category
- У меня есть класс категории, который представляет собой дерево MPTT (потому что моя категоризация является иерархической)
Теперь у меня есть настоящий тест с 7 вопросами и административным представлением, которое показывает вопросы как встроенные в представление QuizzAdmin, а встроенные строки содержат поле Category as Select.
Затем возникает проблема:
- У меня были вопросы, загруженные как prefetch_related (и даже пытался, чтобы вопросы__category) были загружены таким образом
- Несмотря на это, я вижу свою панель инструментов отладки, показывающую серию из 16 запросов, происходящих во время рендеринга шаблона (template / edit_inline / tabular.html). На моем ноутбуке разработчика это означает 1 минуту для загрузки всего этого (а в моей тестовой среде с фактическими данными это означает 10 минут!)
Эти 16 запросов являются последовательностью следующих: (пожалуйста, обратите внимание, что я тестируюсь с фиктивными категориями)
SELECT "quizz_category"."id", "quizz_category"."parent_id", "quizz_category"."name",
"quizz_category"."name_en", "quizz_category"."name_fr", "quizz_category"."lft",
"quizz_category"."rght", "quizz_category"."tree_id", "quizz_category"."level",
"quizz_category"."description", "quizz_category"."description_en",
"quizz_category"."description_fr" FROM "quizz_category" ORDER BY
"quizz_category"."tree_id" ASC, "quizz_category"."lft" ASC
а также
SELECT "quizz_category"."id", "quizz_category"."parent_id", "quizz_category"."name",
"quizz_category"."name_en", "quizz_category"."name_fr", "quizz_category"."lft",
"quizz_category"."rght", "quizz_category"."tree_id", "quizz_category"."level",
"quizz_category"."description", "quizz_category"."description_en",
"quizz_category"."description_fr" FROM "quizz_category" WHERE ("quizz_category"."lft" <= 3
AND "quizz_category"."rght" >= 6 AND "quizz_category"."tree_id" = 1 ) ORDER BY
"quizz_category"."lft" ASC
Есть идеи, что я могу сделать, чтобы уменьшить количество запросов?
Спасибо вперед, Лос-Анджелес
[ИЗМЕНИТЬ 1]
Была одна глупая вещь, которая объясняет половину проблемы: __unicode __ () моей категории смотрел на __unicode __ () родителей объекта (к счастью, мое дерево всего на 2 уровня)
Теперь в моей оптимальной конфигурации у меня все еще есть 9 раз «SELECT ... FROM quizz_category» (без предложения WHERE) для 8 записей, предположительно для создания вариантов выбора в поле Select.
Кто-нибудь знает, как кэшировать этот запрос и запускать его только один раз?
Примечание: моя текущая оптимальная конфигурация - иметь .select_related ('category') в QuestionInline
class QuestionInline(admin.TabularInline): # admin.StackedInline
model = Question
extra = 0
ordering = ['position',]
def queryset(self, request):
return super(QuestionInline, self).queryset(request).select_related('category')
class QuizzAdmin(admin.ModelAdmin):
list_display = ["name","rating_scale"]
inlines = [QuestionInline]
fieldsets = (
(None, {'fields': (('name'), ('type',), 'description',
'rating_scale' )}),
)
def queryset(self, request):
if getattr(self,'is_change_list', False):
# it's a changelist view, we don't need details on ForeignKey-accessible objects
return super(QuizzAdmin, self).queryset(request)
else:
return super(QuizzAdmin, self).queryset(request).select_related('rating_scale')
def changelist_view(self, request, extra_context=None):
self.is_change_list = True
return super(QuizzAdmin, self).changelist_view(request, extra_context)
class Category(AbstractAnalyticTreeCategory):
description = BusinessTextField(_("description")) # basically a text field of mine
tree = AnalyticTreeManager()
def __unicode__(self):
return self.name
class Quizz(models.Model):
name = models.CharField(_("name of the quizz"), unique=True, max_length=60)
description = BusinessTextField(_("description"))
type = models.CharField(_("type"), choices=QUIZZ_TYPE_CHOICES, default=QUIZZ_SELF_EVALUATION, null=False, blank=False, max_length=2)
rating_scale = models.ForeignKey(MCQScale, verbose_name=_("applicable rating scale"), on_delete=models.PROTECT)
def __unicode__(self):
return self.name
class Question(models.Model):
position = models.IntegerField(verbose_name=_("order index"), help_text=_("Order in which the question will appear."))
quizz = models.ForeignKey(Quizz, verbose_name=_("Related quizz"), null=False, blank=False, related_name='questions')
title = BusinessCharField(_("item"), max_length=60, null=True, blank=True)
text = BusinessTextField(_("question text"),)
category = TreeForeignKey(Category, verbose_name=_("dimension"), null=True, blank=False, on_delete=models.SET_NULL)
def __unicode__(self):
return self.title
Вот что говорит об этих запросах панель отладки (все равно):
SELECT "quizz_category"."id", "quizz_category"."parent_id", "quizz_category"."name", "quizz_category"."name_en", "quizz_category"."name_fr", "quizz_category"."lft", "quizz_category"."rght", "quizz_category"."tree_id", "quizz_category"."level", "quizz_category"."description", "quizz_category"."description_en", "quizz_category"."description_fr" FROM "quizz_category" ORDER BY "quizz_category"."tree_id" ASC, "quizz_category"."lft" ASC 3,68816058264% 1,66 Sel Expl Connection: default Isolation Level: Read committed Transaction Status: In transaction /Library/Python/2.7/site-packages/django/contrib/staticfiles/handlers.py in call(72) return self.application(environ, start_response) /Library/Python/2.7/site-packages/django/contrib/admin/widgets.py in render(263) output = [self.widget.render(name, value, *args, **kwargs)] 49
{{ field.contents|linebreaksbr }}
50 {% else %} 51
{{ field.field.errors.as_ul }} 52
{{ field.field }} 53
{% endif %} 54
55
{% endfor %} /Library/Python/2.7/site-packages/django/contrib/admin/templates/admin/edit_inline/tabular.html