1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Fix natural ordering within object tables

This commit is contained in:
Jeremy Stretch
2018-06-11 15:10:31 -04:00
parent 048e843c39
commit 90abeedc3e
3 changed files with 33 additions and 30 deletions

View File

@@ -4,29 +4,35 @@ from django.db.models import Manager
class NaturalOrderByManager(Manager):
"""
Order objects naturally by a designated field. Leading and/or trailing digits of values within this field will be
cast as independent integers and sorted accordingly. For example, "Foo2" will be ordered before "Foo10", even though
the digit 1 is normally ordered before the digit 2.
"""
natural_order_field = None
def natural_order_by(self, *fields):
"""
Attempt to order records naturally by segmenting a field into three parts:
def get_queryset(self):
1. Leading integer (if any)
2. Middle portion
3. Trailing integer (if any)
queryset = super(NaturalOrderByManager, self).get_queryset()
:param fields: The fields on which to order the queryset. The last field in the list will be ordered naturally.
"""
db_table = self.model._meta.db_table
primary_field = fields[-1]
db_field = self.natural_order_field
id1 = '_{}_{}1'.format(db_table, primary_field)
id2 = '_{}_{}2'.format(db_table, primary_field)
id3 = '_{}_{}3'.format(db_table, primary_field)
queryset = super(NaturalOrderByManager, self).get_queryset().extra(select={
id1: "CAST(SUBSTRING({}.{} FROM '^(\d{{1,9}})') AS integer)".format(db_table, primary_field),
id2: "SUBSTRING({}.{} FROM '^\d*(.*?)\d*$')".format(db_table, primary_field),
id3: "CAST(SUBSTRING({}.{} FROM '(\d{{1,9}})$') AS integer)".format(db_table, primary_field),
# Append the three subfields derived from the designated natural ordering field
queryset = queryset.extra(select={
'_nat1': "CAST(SUBSTRING({}.{} FROM '^(\d{{1,9}})') AS integer)".format(db_table, db_field),
'_nat2': "SUBSTRING({}.{} FROM '^\d*(.*?)\d*$')".format(db_table, db_field),
'_nat3': "CAST(SUBSTRING({}.{} FROM '(\d{{1,9}})$') AS integer)".format(db_table, db_field),
})
ordering = fields[0:-1] + (id1, id2, id3)
# Replace any instance of the designated natural ordering field with its three subfields
ordering = []
for field in self.model._meta.ordering:
if field == self.natural_order_field:
ordering.append('_nat1')
ordering.append('_nat2')
ordering.append('_nat3')
else:
ordering.append(field)
return queryset.order_by(*ordering)