Opened 14 years ago
Last modified 13 months ago
#14336 new New feature
list_display should be able to contain sortable references to annotated fields
Reported by: | Paul McLanahan | Owned by: | |
---|---|---|---|
Component: | contrib.admin | Version: | 1.2 |
Severity: | Normal | Keywords: | |
Cc: | riccardo.magliocchetti@…, jon.c.culver@…, Olivier Dalang | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | yes |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Overriding the queryset
method of a ModelAdmin
should be an easy way to annotate the QuerySet
used in the admin list view for a model. My use case is that I have two IntegerField
s containing counts of various things, but what I'd like to be able to display and sort by in the admin list view is the sum of these two fields. This can best be explained by an example:
# Given this model class Article(models.Model): title = models.CharField(max_length=255) num_a = models.PositiveIntegerField() num_b = models.PositiveIntegerField() # Want ModelAdmin like... class ArticleAdmin(admin.ModelAdmin): list_display = ('title' 'total_nums') def queryset(self, request): qs = super(ArticleAdmin, self).queryset(request) return qs.extra(select={'total_nums':'num_a + num_b'})
This fails at model validation with a ImproperlyConfigured
exception in django.contrib.admin.validation.validate
because the model has no 'total_nums' field, which we know. But the model validation mechanism has no access to the instance of the ModelAdmin
, and therefore no access to the queryset to be able to check for any extras or annotations.
I tried fixing this and would have submitted a patch, but I failed in the time I had. However, there is a workaround I discovered and am using, but it seems silly. You change ArticleAdmin
to the following:
class ArticleAdmin(admin.ModelAdmin): list_display = ('title' 'total') def total(self, obj): return obj.total_nums total.admin_order_field = 'total_nums' def queryset(self, request): qs = super(ArticleAdmin, self).queryset(request) return qs.extra(select={'total_nums':'num_a + num_b'})
This seems overly verbose and a little hacky, but it does work. I'd say that makes this ticket non-urgent, though I do wonder how many developers gave up before discovering this technique.
Change History (10)
comment:1 by , 14 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → New feature |
comment:5 by , 11 years ago
Cc: | added |
---|
comment:6 by , 10 years ago
Cc: | added |
---|---|
Has patch: | set |
Needs documentation: | set |
Owner: | changed from | to
Status: | new → assigned |
I had a use case specific to counts, so I took a crack at addressing this — and it's my first contribution, so feedback is wholly welcomed and appreciated.
https://github.com/bahoo/django/compare/django:stable/1.7.x...ticket_14336_1_7?expand=1
This adds list_annotate
which can be populated with any aggregate to a related object or ManyToMany field, though Count
is the only pertinent one here, I suspect.
with models.py
class Programmer(models.Model): pass class Software(models.Model): title = models.CharField(max_length=30) contributors = models.ManyToManyField('Programmer') class Commit(models.Model): project = models.ForeignKey(Software, related_name='commits') author = models.ForeignKey(Programmer)
and admin.py
from django.db import Count from django.contrib import admin from .models import Software @admin.register(Software) class SoftwareAdmin(admin.ModelAdmin): list_display = ('title', 'contributors__count', 'commits__count') list_annotate = [Count('contributors'), Count('commits')]
'Contributors count' and 'Commits count' become two sortable columns in the changelist admin.
I'm happy to add the above example to the documentation and submit a pull request, but could I trouble someone for some feedback on my approach? Thank you!
comment:7 by , 8 years ago
Summary: | list_display should be able to contain sortable references to extra and/or annotated fields → list_display should be able to contain sortable references to annotated fields |
---|
I'm removing consideration of "extra" fields from the summary because QuerySet.extra()
is now discouraged and likely to be deprecated in the future.
#27229 is a related ticket that suggests allowing aggregations in list_display
. I hope to figure out a suitable path forward for this on the django-developers mailing list thread. Jon, sorry you didn't get any feedback from your original work. Feel free to chime in here if you still have time and interest in working on this.
comment:8 by , 8 years ago
Sure, I'd love to help. I'll have more free time to devote to it come mid-November, would that work? Thanks, Tim.
comment:9 by , 2 years ago
Owner: | removed |
---|---|
Status: | assigned → new |
comment:10 by , 13 months ago
Cc: | added |
---|
We don't really want to encourage the use of
extra
in general, however making additional queryset attributes available inlist_display
could be quite useful when used in conjunction withannotate
.