#26524 closed Cleanup/optimization (fixed)
Change foreign key id list_display reference to display only the id
Reported by: | Cristiano Coelho | Owned by: | nobody |
---|---|---|---|
Component: | contrib.admin | Version: | dev |
Severity: | Release blocker | Keywords: | admin list_display changelist |
Cc: | Cristiano Coelho, krishna.bmsce@…, zachborboa@… | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Given these two models.
class A(models.Model): name = models.CharField(max_length=100) def __unicode__(self): return self.name class B(models.Model): name = models.CharField(max_length=100) fk = models.ForeignKey(A) def __unicode__(self): return self.name
And these model admin
class AAdmin(admin.ModelAdmin): list_display = ('id','name') admin.site.register(A, AAdmin) class BAdmin(admin.ModelAdmin): list_display = ('id','name','fk_id','fk') admin.site.register(B, BAdmin)
As you see, for BAdmin I'm trying to display the actual id of the foreign key, so I prevent an additional unwanted join (or worse, one query per related object if no select related is added). However, the admin page refuses to display the id and instead renders the whole object (calling the unicode method) which causes the additional join I don't want.
In order to demostrate it I also added the 'fk' relation which works as expected
The change list result is then
1 test B test A test A
where it should be
1 test B 1 test A
In order to work around it, I can define a callable that just returns the id property, but that's terrible because I lose any sort option on it plus I need to write quite a few more lines.
Attachments (1)
Change History (21)
comment:1 by , 9 years ago
Summary: | Django Admin list_display - Unable to display foreign key id → Change foreign key id list_display reference to display only the id |
---|---|
Triage Stage: | Unreviewed → Accepted |
Type: | Bug → Cleanup/optimization |
comment:2 by , 9 years ago
Is there any specific reason that using 'fk_id' and just 'fk' causes both to actually fetch the object? I'm expecting that if I access fk_id I am actually accessing the attribute and not the relation.
It is the same case when working with instances:
b = B.objects.first() print b.fk_id --> prints the id/value print b.fk --> fetchs the relation and call the actual object __unicode__
So for me this working different when using the ModelAdmin and display_list looks like a bug rather than a cleanup, you have two properties performing the exact same action.
comment:3 by , 9 years ago
@cristianocca and @tim, the has_related_field_in_list_display
method of ChangeList
class in django.contrib.admin.views.main
makes use of the django.db.models.options:Options._forward_fields_map
which treats the _id attribute in a similar way and the same has been documented there - https://github.com/django/django/blob/master/django/db/models/options.py#L469 it specifically talks about the *_id fields as well.
comment:4 by , 9 years ago
So actually changing this could break a few things? Any other work around that could let you use the *_id field but still allow for sorting of that column, which using a custom callable prevents?
comment:5 by , 9 years ago
Not necessarily, changing it at the admin list_display
level might be feasible.
comment:6 by , 9 years ago
Cc: | added |
---|
comment:7 by , 9 years ago
@timgraham, I have submitted a pull request for the same https://github.com/django/django/pull/6497
Will be happy to know if there are any better ways of doing this.
comment:8 by , 9 years ago
Has patch: | set |
---|
Please check "Has patch" so the ticket appears in the review queue.
comment:10 by , 9 years ago
Cc: | added |
---|
comment:11 by , 8 years ago
Description: | modified (diff) |
---|
comment:12 by , 8 years ago
@timgraham, Any update on this? Will be glad to work on anything that can make the review and merge process easy w.r.t this patch.
comment:13 by , 8 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
In f6681393d3f53a67b4e0645e8d02f95579d8ae2d:
Fixed #26524 -- Made a foreign key id reference in ModelAdmin.list_display display the id.
comment:15 by , 8 years ago
Has patch: | unset |
---|---|
Severity: | Normal → Release blocker |
Version: | 1.9 → master |
This caused a regression in using a ManyToManyField
in ModelAdmin.readonly_fields
. I'm attaching a regression test that passes on the stable/1.10.x branch. The {% include %}
in the admin template started silently failing in the commit for this ticket and then in 331ca5391eb64cbac3a001209257beb93522d587, that silent failure become an exception because of the deprecation warning. Fixing this will also fix the two selenium test failures that use the Pizza
admin.
comment:16 by , 8 years ago
Resolution: | fixed |
---|---|
Status: | closed → new |
by , 8 years ago
Attachment: | 26524-regress.diff added |
---|
comment:17 by , 8 years ago
Has patch: | set |
---|
If I understand the surrounding code and intentions correctly, I think the PR fixes the regression by changing the condition from:
# Avoid coercing <FK>_id fields to FK if field.is_relation and hasattr(field, 'attname') and field.attname == name: raise FieldIsAForeignKeyColumnName()
To
# Avoid coercing <FK>_id fields to FK if field.is_relation and not field.many_to_many and hasattr(field, 'attname') and field.attname == name: raise FieldIsAForeignKeyColumnName()
But it would help if someone with a deeper understanding of the original change, admin, and relationship fields had a look to make sure I'm not introducing a different edge case crash. Thanks for any feedback.
comment:18 by , 8 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
Seems reasonable, though is backwards-incompatible -- hopefully not too many people will be affected by the change but I'd mention it in the release notes.