#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.

Reply via email to