Производительность Django с M2M - PullRequest
2 голосов
/ 03 июля 2011

У меня есть модель, которая выглядит так:

class ParentObject(models.Model):
  ...
  services = models.ManyToManyField(Service)

class ChildObject(models.Model):
  parent = models.ForeignKey(ParentObject)
  services = models.ManyToManyField(Service)

class Service(models.Model):
  name = ...
  description = ...

Итак, в итоге, к объекту прикреплен список сервисов, а к дочерним объектам должны быть прикреплены другие сервисы.

По размеру у каждого Родителя есть список из 50-60 Услуг, а у каждого Ребенка (по 5 на Родителя) список из 30-40 Услуг. В django-admin (используя, кстати, grappelli) я установил Child в строку.

Проблема в том, что страница администратора загружается очень тяжело (3-5 секунд), потому что Django Admin выполняет около 1200 запросов (чтобы получить Сервис каждый раз - иногда несколько раз), чтобы показать мне информацию для редактирования.

Знаете ли вы какие-либо советы / хитрости для оптимизации этого?

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 03 июля 2011

Я не играл с grappelli, но в стандартном django-admin я бы рассмотрел использование: ModelAdmin.raw_id_fields. Ограничение заключается в том, что вы выбираете сервисы не по имени, а по имени pk.

По умолчанию администратор Django использует интерфейс выбора блока () для поля, которые являются ForeignKey. Иногда Вы не хотите нести накладные расходы о необходимости выбора всех связанных экземпляры для отображения в раскрывающемся списке.

raw_id_fields - это список полей, которые вы хотел бы изменить на вход виджет для ForeignKey или ManyToManyField:

class ArticleAdmin(admin.ModelAdmin):
    raw_id_fields = ("newspaper",)

Более сложный подход - переопределить администратор администратора для Service и добавить кэш уровня запросов. Не забудьте сделать этот менеджер доступным в случае доступа к приподнятым объектам.

1 голос
/ 04 июля 2011

Вам необходимо переопределить метод набора запросов администратора и добавить в него select_related, поместить его в свой файл admin.py

class ServiceAdmin(admin.ModelAdmin):
    ...

    def queryset(self, request):
        qs = super(ServiceAdmin, self).queryset(request)
        return qs.select_related()

admin.site.register(Service, ServiceAdmin)

Это само по себе должно немного уменьшить ваши запросы, но основная проблема заключается в том, чточто Django select_related не следует автоматически за ManyToMany.Вы должны сделать некоторые дополнительные обходные пути для этого.Я бы использовал prefill_entry_list из FeinCMS приложения, чтобы сделать это.

...