#34566: ModelAdmin get_field_queryset uses related admin ordering, but not
related
admin querysets.
-------------------------------------------+------------------------
Reporter: Sodium-Hydrogen | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 4.2
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 1
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------------+------------------------
The ModelAdmin get_field_queryset function properly finds the related
model admin and gets the ordering from that. However, it does not also get
the fully annotated queryset which can lead to errors breaking the admin
page.
In my case I created my own User admin page and added the user permission
count to the queryset as follows:
{{{
class UserLocalAdmin(UserAdmin):
def custom_perm_count(user):
return user.user_permissions__count
custom_perm_count.admin_order_field = "user_permissions__count"
custom_perm_count.short_description = "Permission Count"
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.annotate(models.Count("user_permissions"))
list_display = ("username", "email", "is_staff", "is_superuser",
custom_perm_count, "is_active","last_login")
sortable_by = list_display
ordering = ("-is_active", "-user_permissions__count", "-is_superuser",
"username")
}}}
Then in a different model I use user as a foreign key titled owner. I also
created an admin page for that model.
The issue is the drop down list created for the "owner" foreign key field
fetches the admin page ordering, but the un-altered queryset.
This causes a FieldError to be raised and django fails to load the page.
Currently the only option I can see to handle this would be override the
get_field_queryset function and allow it to reference the get_queryset
function or provide custom ordering.
{{{
class ReportFilterAdmin(dj_admin.ModelAdmin):
form=AdminReportFilterForm
def get_field_queryset(self, db, db_field, request):
"""
An override of the original to add the required annotations.
If the ModelAdmin specifies ordering, the queryset should respect
that
ordering. Otherwise don't specify the queryset, let the field
decide
(return None in that case).
"""
related_admin =
self.admin_site._registry.get(db_field.remote_field.model)
if related_admin is not None:
ordering = related_admin.get_ordering(request)
if ordering is not None and ordering != ():
# return
db_field.remote_field.model._default_manager.using(db).order_by( # current
line in official repo
return related_admin.get_queryset(request).order_by(
*ordering
)
return None
}}}
I don't know if there are performance issues with my approach, but I
believe it achieves more universally expected behavior.
original code:
[https://github.com/django/django/blob/7414704e88d73dafbcfbb85f9bc54cb6111439d3/django/contrib/admin/options.py#L253-L255]
--
Ticket URL: <https://code.djangoproject.com/ticket/34566>
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 view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/01070188209a846c-3a3c8314-1288-4e82-9522-a5f084b00d71-000000%40eu-central-1.amazonses.com.