#25299: Backwards compatibility issue with list_display callable names
-------------------------------+----------------------------------------
     Reporter:  scoenye        |      Owner:  nobody
         Type:  Bug            |     Status:  new
    Component:  Uncategorized  |    Version:  1.8
     Severity:  Normal         |   Keywords:  list_display callable name
 Triage Stage:  Unreviewed     |  Has patch:  0
Easy pickings:  0              |      UI/UX:  0
-------------------------------+----------------------------------------
 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.

--
Ticket URL: <https://code.djangoproject.com/ticket/25299>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.83a0974d0481022eb4cf0d524ebe3aad%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to