Как заставить Django Admin использовать select_related?
Одна из моих моделей особенно сложна. Когда я пытаюсь редактировать его в Django Admin, он выполняет 1042 запроса и занимает более 9 секунд для обработки.
Я знаю, что я могу заменить несколько выпадающих списков на raw_id_fields
, но я думаю, что более узким местом является то, что он не выполняет select_related()
, как должен.
Могу ли я получить сайт администратора для этого?
Ответы
Ответ 1
Хотя ответ dr jimbob имеет смысл, для моих нужд я смог просто переопределить метод get_queryset() с помощью однострочного интерфейса, даже выбрав внешний ключ внешнего ключа. Возможно, это может быть полезно кому-то.
class MyModelAdmin(admin.ModelAdmin):
model = MyModel
...
def get_queryset(self, request):
return super(MyModelAdmin, self).get_queryset(request).select_related(
'foreign_key1', 'foreign_key2__fk2_foreign_key')
Ответ 2
вы можете попробовать это
class Foo(admin.ModelAdmin):
list_select_related = (
'foreign_key1',
'foreign_key2',
)
https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_select_related
Ответ 3
Для моей конкретной модели особенно медленный аспект проходит через ForeignKeys, когда они отображаются в формах, которые не называются с помощью select_related
, так что часть, которую я собираюсь ускорить.
Просматривая соответствующий источник django, вы видите в django/contrib/admin/options.py
, что метод formfield_for_foreignkeys
принимает каждый FK db_field
и вызывает метод ForeignKey
class formfield
, который определен в django/db/models/поля/связанные/как:
def formfield(self, **kwargs):
db = kwargs.pop('using', None)
defaults = {
'form_class': forms.ModelChoiceField,
'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to),
'to_field_name': self.rel.field_name,
}
defaults.update(kwargs)
return super(ForeignKey, self).formfield(**defaults)
Из этого мы видим, если мы предоставляем db_field
с помощью kwargs['queryset']
, мы можем определить пользовательский набор запросов, который будет использоваться select_related (это может быть предоставлено formfield_for_foreignkey
).
Итак, в основном мы хотим переопределить admin.ModelAdmin
с помощью SelectRelatedModelAdmin
, а затем сделать наши подклассы ModelAdmin SelectRelatedModelAdmin
вместо admin.ModelAdmin
class SelectRelatedModelAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if 'queryset' in kwargs:
kwargs['queryset'] = kwargs['queryset'].select_related()
else:
db = kwargs.pop('using', None)
kwargs['queryset'] = db_field.rel.to._default_manager.using(db).complex_filter(db_field.rel.limit_choices_to).select_related()
return super(SelectRelatedModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Этот пример кода не охватывает admin Inline
или ManyToManyField
s, либо обход foreign_key в функциях, вызываемых readonly_fields
или пользовательскими select_related запросами, но аналогичный подход должен работать для этих случаев.