One of my models is particularily complex. When I try to edit it in Django Admin it performs 1042 queries and takes over 9 seconds to process.
I know I can replace a few of the drop-downs with raw_id_fields
, but I think the bigger bottleneck is that it's not performing a select_related()
as it should.
Can I get the admin site to do this?
Although dr jimbob's answer makes sense, for my needs, I was able to simply override the get_queryset() method with a one-liner, even selecting a foreign key's foreign key. Maybe this could be helpful to someone.
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')
you can try this
class Foo(admin.ModelAdmin):
list_select_related = (
'foreign_key1',
'foreign_key2',
)
For my particular model, the particularly slow aspect is going through ForeignKeys when they were being displayed in forms, which aren't called using select_related
, so that's the part I'm going to speed up.
Looking through the relevant django source, you see in django/contrib/admin/options.py
that the method formfield_for_foreignkeys
takes each FK db_field
and calls the ForeignKey
class's formfield
method, which is defined in django/db/models/fields/related/ like:
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)
From this, we see if we provide the db_field
with a kwargs['queryset']
we can define a custom queryset that will be use select_related (this can be provided by formfield_for_foreignkey
).
So basically what we want to do is override admin.ModelAdmin
with SelectRelatedModelAdmin
and then make our ModelAdmin subclasses of SelectRelatedModelAdmin
instead of 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)
This code sample doesn't cover admin Inline
s or ManyToManyField
s, or foreign_key traversal in functions called by readonly_fields
or custom select_related queries, but a similar approach should work for those cases.
In Django 2.0+, a good way to improve performance of ForeignKey and ManyToMany relationships is to use autocomplete fields.
These fields don't show all related objects and therefore load with many fewer queries.
来源:https://stackoverflow.com/questions/6892906/how-to-force-django-admin-to-use-select-related