contrib.admin:list_editable - ForeignKey performance is O(m*n)
|Reported by:||chadc||Owned by:||nobody|
|Severity:||Normal||Keywords:||list_editable, admin, ForeignKey, admin efficiency|
|Cc:||chadcogar@…, kissgyorgy@…||Triage Stage:||Accepted|
|Has patch:||no||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
Including ForeignKey fields in list_editable results in m*n database queries where m is the number of ForeignKey fields in list_editable and n is the number of rows in the changelist.
I have been experiencing poor performance with the admin changelist when list_editable includes ForeignKey fields. In particular, rendering the changelist requires O(m*n) database queries where m is the number of ForeignKey fields included in list_editable and n is the number of rows in the changelist. The problem, as I understand it, stems from the fact that the choices for the ForeignKey widgets are not cached. So, when each ForeignKey widget is rendered, it queries the database to retrieve the list of possible values.
My solution to this problem has been to override the Select widget with a CachedSelect widget in the admin model. However, as Jeremy Dunck noted in django-developers (link below), this may stem from a more general problem with ModelFormSet. I have ticketed this under contrib.admin for now, but I hope that Jeremy will update it as any larger issues become clear.
class Host(models.Model): name = models.CharField(max_length=128, unique=True) class Account(models.Model): host = models.ForeignKey(Host, related_name="accounts") name = models.CharField(max_length=128) class AccountAdmin(admin.ModelAdmin): list_display = ('name', 'host') list_editable = ('host',) list_per_page = 25 admin.site.register(Account, AccountAdmin)
Rendering the ForeignKey widgets in this example requires n*m=25*1=25 database queries:
SELECT "hosts_host"."id", "hosts_host"."name" FROM "hosts_host" ORDER BY "hosts_host"."name" ASC
Total time: 330 ms
Numer of queries: 25