#10722 closed (invalid)
Changelist view does not use select_related() on a nullable foreign key
Reported by: | mrts | Owned by: | nobody |
---|---|---|---|
Component: | contrib.admin | Version: | dev |
Severity: | Keywords: | efficient-admin | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Given the following models.py
:
from django.db import models class Base(models.Model): name = models.CharField(max_length=10) lots_of_text = models.TextField() class Meta: abstract = True def __unicode__(self): return self.name class A(Base): a_field = models.CharField(max_length=10) class B(Base): b_field = models.CharField(max_length=10) class C(Base): a = models.ForeignKey(A) b = models.ForeignKey(B) is_published = models.BooleanField()
and the following admin.py
:
from django.contrib import admin from improve_admin.models import A, B, C class CAdmin(admin.ModelAdmin): list_display = ('name', 'a', 'b', 'is_published') admin.site.register(A) admin.site.register(B) admin.site.register(C, CAdmin)
select_related()
is used as documented in http://docs.djangoproject.com/en/dev/ref/contrib/admin/#list-select-related , resulting in the following query:
SELECT "improve_admin_c"."id", "improve_admin_c"."name", "improve_admin_c"."lots_of_text", "improve_admin_c"."a_id", "improve_admin_c"."b_id", "improve_admin_c"."is_published", "improve_admin_a"."id", "improve_admin_a"."name", "improve_admin_a"."lots_of_text", "improve_admin_a"."a_field", "improve_admin_b"."id", "improve_admin_b"."name", "improve_admin_b"."lots_of_text", "improve_admin_b"."b_field" FROM "improve_admin_c" INNER JOIN "improve_admin_a" ON ("improve_admin_c"."a_id" = "improve_admin_a"."id") INNER JOIN "improve_admin_b" ON ("improve_admin_c"."b_id" = "improve_admin_b"."id") ORDER BY "improve_admin_c"."id" DESC
Setting one foreign key field to be nullable:
# diff between the original and new models.py class C(Base): - a = models.ForeignKey(A) + a = models.ForeignKey(A, blank=True, null=True) b = models.ForeignKey(B)
results in the following SQL:
SELECT "improve_admin_c"."id", "improve_admin_c"."name", "improve_admin_c"."lots_of_text", "improve_admin_c"."a_id", "improve_admin_c"."b_id", "improve_admin_c"."is_published", "improve_admin_b"."id", "improve_admin_b"."name", "improve_admin_b"."lots_of_text", "improve_admin_b"."b_field" FROM "improve_admin_c" INNER JOIN "improve_admin_b" ON ("improve_admin_c"."b_id" = "improve_admin_b"."id") ORDER BY "improve_admin_c"."id" DESC
and additional n
queries for each of the referred a
fields:
SELECT "improve_admin_a"."id", "improve_admin_a"."name", "improve_admin_a"."lots_of_text", "improve_admin_a"."a_field" FROM "improve_admin_a" WHERE "improve_admin_a"."id" = 2
Change History (5)
comment:1 by , 16 years ago
Component: | Uncategorized → django.contrib.admin |
---|
comment:2 by , 16 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
comment:5 by , 16 years ago
Keywords: | efficient-admin added |
---|
Note:
See TracTickets
for help on using tickets.
Admin doesn't introspect the model and decide not to use select_related() if null=True on a ForeignKey. Rather, select_related() itself does not follow null=True ForeignKeys, as documented: http://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related
"Note that, by default, select_related() does not follow foreign keys that have null=True."
This strikes me as another case where if you want to control the queries the admin is going to issue to this level of detail, you'll need to specify the ModelAdmin queryset() yourself.