allow list_display in admin to traverse onetoonfields and foreign key relations

300 views
Skip to first unread message

Wim Feijen

unread,
Feb 25, 2014, 6:48:40 PM2/25/14
to django-d...@googlegroups.com
Hello,

Right now I have a School model containing a OneToOne-relation to User.

In the admin, in search_fields, I can use double underscores to search in related fields, for example:
    search_fields = ('place__name', 'school__name')

But in list_display, I can't. For example,
    list_display = ['school', 'school__user', 'place', ]
gives an error.

I find this totally confusing. More people do.

A ticket has been made six years ago and was eventually closed as won't fix. Currently, the proposed solution is to write a custom method or callable. I'd like to raise a discussion to reopen that ticket.

For reference, see:

My arguments to allow such a syntax are:

1. allowing 'school__user' in list_display is consistent with the behaviour of search_fields, list_filter in the admin, and get() and filter() query syntax in general.
2. it saves many people duplicating two to four lines of custom code, and in my opinion, allows for a more concise yet extremely easy to understand notation.
3. ideally, a solution would use select_related in order to save database queries and thus be longer than two to four lines of code.
4. the need is common, and in onetoonefields specifically. Many people have expressed their interest in this feature, and a core developer initially accepted it.
5. a long time has passed since then and our policy of accepting tickets has changed.

Thanks for reading! I'd love to hear your response.

Regards, Wim

Zach Borboa

unread,
Feb 26, 2014, 12:49:51 AM2/26/14
to django-d...@googlegroups.com
I agree that the current behaviour is confusing and needs change in order to be DRY[1] and consistent[2].




This is how I currently work around this issue.

models.py
class Question(models.Model):
    text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    question = models.ForeignKey(Question)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

admin.py
class ChoiceAdmin(admin.ModelAdmin):
    def question__text(self, obj):
        return obj.question.text

    list_display = ('pk', 'question__text', 'choice_text', 'votes')

admin.site.register(Choice, ChoiceAdmin)

Gwildor Sok

unread,
Feb 26, 2014, 8:11:51 AM2/26/14
to django-d...@googlegroups.com
Personally I usually use lambda's, which saves another line of code:
class ChoiceAdmin(admin.ModelAdmin):
    question__text = lambda s, o: o.question.text 
    list_display = ('pk', 'question__text', 'choice_text', 'votes')


Russell Keith-Magee

unread,
Feb 26, 2014, 7:02:46 PM2/26/14
to Django Developers
Hi Wim,

On Wed, Feb 26, 2014 at 7:48 AM, Wim Feijen <w...@go2people.nl> wrote:
Hello,

Right now I have a School model containing a OneToOne-relation to User.

In the admin, in search_fields, I can use double underscores to search in related fields, for example:
    search_fields = ('place__name', 'school__name')

But in list_display, I can't. For example,
    list_display = ['school', 'school__user', 'place', ]
gives an error.

I find this totally confusing. More people do.

A ticket has been made six years ago and was eventually closed as won't fix. Currently, the proposed solution is to write a custom method or callable. I'd like to raise a discussion to reopen that ticket.

For reference, see:

My arguments to allow such a syntax are:

1. allowing 'school__user' in list_display is consistent with the behaviour of search_fields, list_filter in the admin, and get() and filter() query syntax in general.

Arguable. As Luke points out in his post to django-dev, the list_display serves a different purpose to search_fields and list_filter. The latter are direct database analogs; the former is a display directive. I agree that consistency is a good thing (I'll even admit that I've inadvertantly put foo__bar in list_display definitions when I wasn't thinking clearly), but as Luke points out, the answer isn't *quite* as simple as "just be consistent", because list_display needs to support modes of interaction that search_fields and list_filter doesn't.

There's also an argument to be made that in order to achieve "consistency", support for dunder syntax should be taken *out* of search_fields and list_filter, to be replaced by richer mechanisms, along the line of custom filter objects. 

2. it saves many people duplicating two to four lines of custom code, and in my opinion, allows for a more concise yet extremely easy to understand notation.

The counterargument to this is that Django should provide a shortcut function to make it easy. Luke even provides a sample implementation on the ticket; if we put this in contrib.admin, your "lines of code" argument would be void.
 
3. ideally, a solution would use select_related in order to save database queries and thus be longer than two to four lines of code.

I'm a little wary about code being too smart, but yes, there's an opportunity for optimisation here.
 
4. the need is common, and in onetoonefields specifically.

I haven't seen any evidence to support this claim. *You* definitely need/want it, and there are a handful of participants on the ticket that clearly want it - but Admin hasn't had this behaviour   since the beginning, and this is the first time in 3 years that the issue has been raised on the mailing list. We haven't been flooded with requests for this feature. 
 
Many people have expressed their interest in this feature, and a core developer initially accepted it.

True - but many more subsequently rejected it, and have provided detailed arguments why.
 
5. a long time has passed since then and our policy of accepting tickets has changed.
 
Erm… it has? That's news to me. 

I'm certainly sympathetic to your request. As I said - I've even made the mistake of assuming this feature exists. However, Luke makes some very valid points in his post that you haven't addressed. 

The two biggest practical issues he raises:

 * Differentiating between '__unicode__' and 'foo__bar'

 * The appropriate default column name for 'foo__bar'

If you've got reponses to these issues, please make them, otherwise, I'm inclined to stick with Luke's analysis. However, I'm a weak -0; I could live with the pragmatic argument that it's more confusing to not have this feature, even though the column naming will likely be weird.  

I *would* however, be in favour of adding a shortcut along the lines of the one Luke provided in the ticket.

Yours,
Russ Magee %-)
Reply all
Reply to author
Forward
0 new messages