Opened 9 years ago

Closed 9 years ago

Last modified 9 years ago

#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)

25299-test.diff (1.4 KB ) - added by Tim Graham 9 years ago.

Download all attachments as: .zip

Change History (6)

comment:1 by Tim Graham, 9 years ago

Component: Uncategorizedcontrib.admin
Severity: NormalRelease blocker
Summary: Backwards compatibility issue with list_display callable namesAdmin crash with the name of a reverse accessor in list_display
Triage Stage: UnreviewedAccepted

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.

by Tim Graham, 9 years ago

Attachment: 25299-test.diff added

comment:2 by Tim Graham, 9 years ago

Owner: changed from nobody to Tim Graham
Status: newassigned

comment:3 by Tim Graham, 9 years ago

Has patch: set

comment:4 by Tim Graham <timograham@…>, 9 years ago

Resolution: fixed
Status: assignedclosed

In 9607a04:

Fixed #25299 -- Fixed crash with ModelAdmin.list_display value that clashes with a model reverse accessor.

comment:5 by Tim Graham <timograham@…>, 9 years ago

In 3cc67a6:

[1.8.x] Fixed #25299 -- Fixed crash with ModelAdmin.list_display value that clashes with a model reverse accessor.

Backport of 9607a0404188bbe612f05216f5a82df26f4b4e80 from master

Note: See TracTickets for help on using tickets.
Back to Top