mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-16 01:27:03 +02:00
Finish multi sort thing
This commit is contained in:
parent
3b173e0ad4
commit
08072f5f09
2 changed files with 90 additions and 18 deletions
|
@ -13,6 +13,8 @@ from epplibwrapper.errors import ErrorCode, RegistryError
|
||||||
from registrar.models.domain import Domain
|
from registrar.models.domain import Domain
|
||||||
from registrar.models.utility.admin_sort_fields import AdminSortFields
|
from registrar.models.utility.admin_sort_fields import AdminSortFields
|
||||||
from registrar.utility import csv_export
|
from registrar.utility import csv_export
|
||||||
|
from registrar.views.utility.mixins import OrderableFieldsMixin
|
||||||
|
from django.contrib.admin.views.main import ORDER_VAR
|
||||||
from . import models
|
from . import models
|
||||||
from auditlog.models import LogEntry # type: ignore
|
from auditlog.models import LogEntry # type: ignore
|
||||||
from auditlog.admin import LogEntryAdmin # type: ignore
|
from auditlog.admin import LogEntryAdmin # type: ignore
|
||||||
|
@ -20,24 +22,73 @@ from django_fsm import TransitionNotAllowed # type: ignore
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class OrderableFieldsMixin:
|
# Based off of this excellent example: https://djangosnippets.org/snippets/10471/
|
||||||
orderable_fk_fields = []
|
class MultiFieldSortableChangeList(admin.views.main.ChangeList):
|
||||||
|
"""
|
||||||
|
This class overrides the behavior of column sorting in django admin tables in order
|
||||||
|
to allow multi field sorting
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
new_class = super().__new__(cls)
|
|
||||||
for field, sort_field in cls.orderable_fk_fields:
|
|
||||||
setattr(new_class, f'get_{field}', cls._create_orderable_field_method(field, sort_field))
|
|
||||||
return new_class
|
|
||||||
|
|
||||||
@classmethod
|
Usage:
|
||||||
def _create_orderable_field_method(cls, field, sort_field):
|
|
||||||
def method(obj):
|
class MyCustomAdmin(admin.ModelAdmin):
|
||||||
attr = getattr(obj, field)
|
|
||||||
return attr
|
...
|
||||||
method.__name__ = f'get_{field}'
|
|
||||||
method.admin_order_field = f'{field}__{sort_field}'
|
def get_changelist(self, request, **kwargs):
|
||||||
method.short_description = field.replace('_', ' ').title()
|
return MultiFieldSortableChangeList
|
||||||
return method
|
|
||||||
|
...
|
||||||
|
|
||||||
|
"""
|
||||||
|
def get_ordering(self, request, queryset):
|
||||||
|
"""
|
||||||
|
Returns the list of ordering fields for the change list.
|
||||||
|
First we check the get_ordering() method in model admin, then we check
|
||||||
|
the object's default ordering. Then, any manually-specified ordering
|
||||||
|
from the query string overrides anything. Finally, a deterministic
|
||||||
|
order is guaranteed by ensuring the primary key is used as the last
|
||||||
|
ordering field.
|
||||||
|
"""
|
||||||
|
params = self.params
|
||||||
|
ordering = list(self.model_admin.get_ordering(request)
|
||||||
|
or self._get_default_ordering())
|
||||||
|
|
||||||
|
if ORDER_VAR in params:
|
||||||
|
# Clear ordering and used params
|
||||||
|
ordering = []
|
||||||
|
|
||||||
|
order_params = params[ORDER_VAR].split('.')
|
||||||
|
for p in order_params:
|
||||||
|
try:
|
||||||
|
none, pfx, idx = p.rpartition('-')
|
||||||
|
field_name = self.list_display[int(idx)]
|
||||||
|
|
||||||
|
order_fields = self.get_ordering_field(field_name)
|
||||||
|
|
||||||
|
if isinstance(order_fields, list):
|
||||||
|
for order_field in order_fields:
|
||||||
|
if order_field:
|
||||||
|
ordering.append(pfx + order_field)
|
||||||
|
else:
|
||||||
|
ordering.append(pfx + order_fields)
|
||||||
|
|
||||||
|
except (IndexError, ValueError) as err:
|
||||||
|
continue # Invalid ordering specified, skip it.
|
||||||
|
|
||||||
|
# Add the given query's ordering fields, if any.
|
||||||
|
ordering.extend(queryset.query.order_by)
|
||||||
|
|
||||||
|
# Ensure that the primary key is systematically present in the list of
|
||||||
|
# ordering fields so we can guarantee a deterministic order across all
|
||||||
|
# database backends.
|
||||||
|
pk_name = self.lookup_opts.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
|
||||||
|
# we add it.
|
||||||
|
ordering.append('-pk')
|
||||||
|
|
||||||
|
return ordering
|
||||||
|
|
||||||
|
|
||||||
class CustomLogEntryAdmin(LogEntryAdmin):
|
class CustomLogEntryAdmin(LogEntryAdmin):
|
||||||
|
@ -578,8 +629,7 @@ class DomainApplicationAdmin(ListHeaderAdmin, OrderableFieldsMixin):
|
||||||
|
|
||||||
orderable_fk_fields = [
|
orderable_fk_fields = [
|
||||||
('requested_domain', 'name'),
|
('requested_domain', 'name'),
|
||||||
# TODO figure out sorting twice at once
|
("submitter", ["first_name"]),
|
||||||
("submitter", "first_name"),
|
|
||||||
("investigator", "first_name"),
|
("investigator", "first_name"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -659,6 +709,9 @@ 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
|
||||||
|
|
|
@ -14,6 +14,25 @@ import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class OrderableFieldsMixin:
|
||||||
|
orderable_fk_fields = []
|
||||||
|
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
new_class = super().__new__(cls)
|
||||||
|
for field, sort_field in cls.orderable_fk_fields:
|
||||||
|
setattr(new_class, f'get_{field}', cls._create_orderable_field_method(field, sort_field))
|
||||||
|
return new_class
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _create_orderable_field_method(cls, field, sort_field):
|
||||||
|
def method(obj):
|
||||||
|
attr = getattr(obj, field)
|
||||||
|
return attr
|
||||||
|
method.__name__ = f'get_{field}'
|
||||||
|
method.admin_order_field = f'{field}__{sort_field}'
|
||||||
|
method.short_description = field.replace('_', ' ').title()
|
||||||
|
return method
|
||||||
|
|
||||||
|
|
||||||
class PermissionsLoginMixin(PermissionRequiredMixin):
|
class PermissionsLoginMixin(PermissionRequiredMixin):
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue