#25299 closed Bug (fixed)
Admin crash with the name of a reverse accessor in list_display
Reported by: | Sven Coenye | Owned by: | Tim Graham |
---|---|---|---|
Component: | contrib.admin | Version: | 1.8 |
Severity: | Release blocker | Keywords: | list_display callable name |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
In contrast to Django 1.7, Django 1.8 does not allow callables in list_display to have the same name as a relation related_name on a model.
Starting with
class SupportItem(models.Model): description = models.CharField(max_length=30) class Hardware(SupportItem): tag = models.IntegerField(unique=True)
and
class Placement(models.Model): support_item = models.ForeignKey("SupportItem") place_date = models.DateTimeField() location = models.CharField(max_length=50, null=True, blank=True)
I have defined a view on the database exposed in Django as
class HardwareLastAssigned(models.Model): hardware = models.OneToOneField(Hardware, primary_key=True, db_column='support_item_id', related_name='last_assigned') location = models.CharField(max_length=50, blank=True)
which gives the last location a hardware item was deployed to.
Under Django 1.7, the following admin code produces a changelist showing each piece of hardware and its current location:
class HardwareAdmin(NavigableModelAdmin): list_display = ['tag', 'placement'] list_display_links = list_display search_fields = ['tag', 'last_assigned__location'] form = HardwareForm ... def placement(self, obj): return obj.last_assigned.location def get_queryset(self, request): hardware = super(HardwareAdmin, self).get_queryset(request) hardware = hardware.select_related("last_assigned") return hardware
Following an upgrade to Django 1.8, the same code crashes with this exception:
AttributeError: 'Hardware' object has no attribute 'placement'
in
File "/home/django/python2.7-django1.8/lib/python2.7/site-packages/django/contrib/admin/utils.py", line 288, in lookup_field
value = getattr(obj, name)
The cause lies in Options.get_field() (django.db.models.options) which under 1.7 only recognized true fields on the model at hand (Hardware), whereas under 1.8, it also reports related models as fields on the model. However, lookup_field can only handle true fields and triggers the exception.
A workaround is to rename the callable so it does not match any related names which may be associated with the model.
The change was made in commit fb48eb05816b1ac87d58696cdfe48be18c901f16 as part of the formalizations of the _meta API.
If nothing else can be done, it may be worth a mention in the list_display documentation as this restriction is not at all obvious (to me) based on the current docs and the 1.8 release notes.
Attachments (1)
Change History (6)
comment:1 by , 9 years ago
Component: | Uncategorized → contrib.admin |
---|---|
Severity: | Normal → Release blocker |
Summary: | Backwards compatibility issue with list_display callable names → Admin crash with the name of a reverse accessor in list_display |
Triage Stage: | Unreviewed → Accepted |
by , 9 years ago
Attachment: | 25299-test.diff added |
---|
comment:2 by , 9 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
This looks like a bug we should fix. Attaching a regression test for Django's test suite. Feel free to tackle it if you have some time.