Администратор Django list_display странно медленно работает с внешними ключами - PullRequest
0 голосов
/ 03 марта 2011

Джанго 1.2.5 Python: 2.5.5

Мой список администраторов спортивных моделей только что стал очень медленным (5 минут на 400 записей). Он возвращался через секунду или около того, пока мы не получили 400 игр, 50 нечетных команд и 2 вида спорта.

Я исправил это ужасным образом, так что я хотел бы посмотреть, видел ли кто-нибудь это раньше. Мое приложение выглядит так:

models:

Sport( models.Model )
    name

Venue( models.Model )
    name

Team( models.Model )
    name

Fixture( models.Model )
    date
    sport = models.ForeignKey(Sport)
    venue = models.ForeignKey(Venue)

TeamFixture( Fixture )
    team1 = models.ForeignKey(Team, related_name="Team 1")
    team2 = models.ForeignKey(Team, related_name="Team 2")


admin:

TeamFixture_ModelAdmin (ModelAdmin)
    list_display = ('date','sport','venue','team1','team2',)

Если я удалю все внешние ключи из list_display, то это быстро. Как только я добавлю какой-либо внешний ключ, медленно.

Я исправил это, используя не внешние ключи, но вычислил их в init модели, так что это работает:

models:

TeamFixture( Fixture )
    team1 = models.ForeignKey(Team, related_name="Team 1")
    team2 = models.ForeignKey(Team, related_name="Team 2")
    sport_name = ""
    venue_name = ""
    team1_name = ""
    team2_name = ""

    def __init__(self, *args, **kwargs):
        super(TeamFixture, self).__init__(*args, **kwargs)

        self.sport_name = self.sport.name
        self.venue_name = self.venue.name
        self.team1_name = self.team1.name
        self.team2_name = self.team2.name

admin:

TeamFixture_ModelAdmin (ModelAdmin)
    list_display = ('date','sport_name','venue_name','team1_name','team2_name',)

Администрирование для всех других моделей в настоящее время работает с несколькими тысячами записей, и все представления на реальном сайте работают нормально.

Ответы [ 3 ]

3 голосов
/ 12 августа 2011

Это сводит меня с ума.Для list_select_related установлено значение True, однако при добавлении внешнего ключа для пользователя в list_display в администраторе создается один запрос на строку, что замедляет листинг.Select_related имеет значение True, поэтому администратор Django не должен вызывать этот запрос в каждой строке.Что происходит?

3 голосов
/ 03 марта 2011

Первое, что я искал, это вызовы из базы данных. Если вы еще этого не сделали, установите django-debug-toolbar . Этот удивительный инструмент позволяет вам проверить все SQL-запросы, выполненные для текущего запроса. Я предполагаю, что их много. Если вы посмотрите на них, вы узнаете, где искать проблему.

Одна проблема, с которой я сам столкнулся: когда метод __unicode__ модели использует внешний ключ, это приводит к одному обращению к базе данных на экземпляр. Я знаю два пути решения этой проблемы:

  • используйте select_related, что обычно является вашей лучшей ставкой.
  • заставьте ваш __unicode__ вернуть статическую строку и переопределить метод save, чтобы соответствующим образом обновить эту строку.
0 голосов
/ 06 февраля 2017

Это очень старая проблема с администратором django и внешними ключами.Здесь происходит то, что всякий раз, когда вы пытаетесь загрузить объект, он пытается получить все объекты этого внешнего ключа.Допустим, вы пытаетесь загрузить прибор несколькими командами (скажем, количество команд около 100), и он будет продолжать включать все 100 команд за один раз.Вы можете попытаться оптимизировать их, используя то, что называется raw_fields.То, что это сделало бы, вместо того, чтобы вызывать все сразу, ограничит количество вызовов и обеспечит, чтобы вызов выполнялся только тогда, когда происходит событие (т.е. когда вы выбираете команду).Если это похоже на беспорядок в пользовательском интерфейсе, вы можете попробовать использовать этот класс:

"""
For Raw_id_field to optimize django performance for many to many fields
"""
class RawIdWidget(ManyToManyRawIdWidget):
    def label_for_value(self, value):
        values = value.split(',')
        str_values = []
        key = self.rel.get_related_field().name
        for v in values:
            try:
                obj = self.rel.to._default_manager.using(self.db).get(**{key: v})
                x = smart_unicode(obj)
                change_url = reverse(
                    "admin:%s_%s_change" % (obj._meta.app_label, obj._meta.object_name.lower()),
                    args=(obj.pk,)
                )
                str_values += ['<strong><a href="%s">%s</a></strong>' % (change_url, escape(x))]
            except self.rel.to.DoesNotExist:
                str_values += [u'No input or index in the db']
        return u', '.join(str_values)

class ImproveRawId(admin.ModelAdmin):
    raw_id_fields = ('created_by', 'updated_by')
    def formfield_for_dbfield(self, db_field, **kwargs):
        if db_field.name in self.raw_id_fields:
            kwargs.pop("request", None)
            type = db_field.rel.__class__.__name__
            kwargs['widget'] = RawIdWidget(db_field.rel, site)
            return db_field.formfield(**kwargs)
        return super(ImproveRawId, self).formfield_for_dbfield(db_field, **kwargs)

Просто убедитесь, что вы наследуете класс должным образом.Я предполагаю что-то вроде TeamFixture_ModelAdmin (ImproveRawIdFieldsForm).Это, скорее всего, даст вам довольно крутой прирост производительности в администраторе django.

...