Fix mixins

This commit is contained in:
zandercymatics 2023-12-15 14:11:44 -07:00
parent 08072f5f09
commit 4515797680
No known key found for this signature in database
GPG key ID: FF4636ABEC9682B7
2 changed files with 36 additions and 17 deletions

View file

@ -22,6 +22,7 @@ from django_fsm import TransitionNotAllowed # type: ignore
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Based off of this excellent example: https://djangosnippets.org/snippets/10471/ # Based off of this excellent example: https://djangosnippets.org/snippets/10471/
class MultiFieldSortableChangeList(admin.views.main.ChangeList): class MultiFieldSortableChangeList(admin.views.main.ChangeList):
""" """
@ -41,6 +42,7 @@ class MultiFieldSortableChangeList(admin.views.main.ChangeList):
... ...
""" """
def get_ordering(self, request, queryset): def get_ordering(self, request, queryset):
""" """
Returns the list of ordering fields for the change list. Returns the list of ordering fields for the change list.
@ -51,17 +53,16 @@ class MultiFieldSortableChangeList(admin.views.main.ChangeList):
ordering field. ordering field.
""" """
params = self.params params = self.params
ordering = list(self.model_admin.get_ordering(request) ordering = list(self.model_admin.get_ordering(request) or self._get_default_ordering())
or self._get_default_ordering())
if ORDER_VAR in params: if ORDER_VAR in params:
# Clear ordering and used params # Clear ordering and used params
ordering = [] ordering = []
order_params = params[ORDER_VAR].split('.') order_params = params[ORDER_VAR].split(".")
for p in order_params: for p in order_params:
try: try:
none, pfx, idx = p.rpartition('-') none, pfx, idx = p.rpartition("-")
field_name = self.list_display[int(idx)] field_name = self.list_display[int(idx)]
order_fields = self.get_ordering_field(field_name) order_fields = self.get_ordering_field(field_name)
@ -83,10 +84,10 @@ class MultiFieldSortableChangeList(admin.views.main.ChangeList):
# ordering fields so we can guarantee a deterministic order across all # ordering fields so we can guarantee a deterministic order across all
# database backends. # database backends.
pk_name = self.lookup_opts.pk.name pk_name = self.lookup_opts.pk.name
if not (set(ordering) & set(['pk', '-pk', pk_name, '-' + pk_name])): if not (set(ordering) & set(["pk", "-pk", pk_name, "-" + pk_name])):
# The two sets do not intersect, meaning the pk isn't present. So # The two sets do not intersect, meaning the pk isn't present. So
# we add it. # we add it.
ordering.append('-pk') ordering.append("-pk")
return ordering return ordering
@ -137,6 +138,16 @@ class AuditedAdmin(admin.ModelAdmin, AdminSortFields):
class ListHeaderAdmin(AuditedAdmin): class ListHeaderAdmin(AuditedAdmin):
"""Custom admin to add a descriptive subheader to list views.""" """Custom admin to add a descriptive subheader to list views."""
def get_changelist(self, request, **kwargs):
"""Returns a custom ChangeList class, as opposed to the default.
This is so we can override the behaviour of the `admin_order_field` field.
By default, django does not support ordering by multiple fields for this
particular field (i.e. self.admin_order_field=["first_name", "last_name"] is invalid).
Reference: https://code.djangoproject.com/ticket/31975
"""
return MultiFieldSortableChangeList
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
if extra_context is None: if extra_context is None:
extra_context = {} extra_context = {}
@ -628,9 +639,9 @@ class DomainApplicationAdmin(ListHeaderAdmin, OrderableFieldsMixin):
] ]
orderable_fk_fields = [ orderable_fk_fields = [
('requested_domain', 'name'), ("requested_domain", "name"),
("submitter", ["first_name"]), ("submitter", ["first_name", "last_name"]),
("investigator", "first_name"), ("investigator", ["first_name", "last_name"]),
] ]
# Filters # Filters
@ -709,9 +720,6 @@ class DomainApplicationAdmin(ListHeaderAdmin, OrderableFieldsMixin):
] ]
filter_horizontal = ("current_websites", "alternative_domains", "other_contacts") filter_horizontal = ("current_websites", "alternative_domains", "other_contacts")
def get_changelist(self, request, **kwargs):
return MultiFieldSortableChangeList
# lists in filter_horizontal are not sorted properly, sort them # lists in filter_horizontal are not sorted properly, sort them
# by website # by website

View file

@ -14,13 +14,14 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class OrderableFieldsMixin: class OrderableFieldsMixin:
orderable_fk_fields = [] orderable_fk_fields = []
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
new_class = super().__new__(cls) new_class = super().__new__(cls)
for field, sort_field in cls.orderable_fk_fields: for field, sort_field in cls.orderable_fk_fields:
setattr(new_class, f'get_{field}', cls._create_orderable_field_method(field, sort_field)) setattr(new_class, f"get_{field}", cls._create_orderable_field_method(field, sort_field))
return new_class return new_class
@classmethod @classmethod
@ -28,9 +29,19 @@ class OrderableFieldsMixin:
def method(obj): def method(obj):
attr = getattr(obj, field) attr = getattr(obj, field)
return attr return attr
method.__name__ = f'get_{field}'
method.admin_order_field = f'{field}__{sort_field}' method.__name__ = f"get_{field}"
method.short_description = field.replace('_', ' ').title()
if isinstance(sort_field, list):
sort_list = []
for sort_field_item in sort_field:
order_field_string = f"{field}__{sort_field_item}"
sort_list.append(order_field_string)
method.admin_order_field = sort_list
else:
method.admin_order_field = f"{field}__{sort_field}"
method.short_description = field.replace("_", " ").title()
return method return method