mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 17:08:41 -06:00
#303: First stab at implementing a natural ordering for sites, racks, and devices
This commit is contained in:
parent
c643e3a74f
commit
b8d7dd170e
@ -9,10 +9,12 @@ from django.db.models import Count, Q, ObjectDoesNotExist
|
|||||||
|
|
||||||
from extras.rpc import RPC_CLIENTS
|
from extras.rpc import RPC_CLIENTS
|
||||||
from utilities.fields import NullableCharField
|
from utilities.fields import NullableCharField
|
||||||
|
from utilities.managers import NaturalOrderByManager
|
||||||
from utilities.models import CreatedUpdatedModel
|
from utilities.models import CreatedUpdatedModel
|
||||||
|
|
||||||
from .fields import ASNField, MACAddressField
|
from .fields import ASNField, MACAddressField
|
||||||
|
|
||||||
|
|
||||||
RACK_FACE_FRONT = 0
|
RACK_FACE_FRONT = 0
|
||||||
RACK_FACE_REAR = 1
|
RACK_FACE_REAR = 1
|
||||||
RACK_FACE_CHOICES = [
|
RACK_FACE_CHOICES = [
|
||||||
@ -137,6 +139,12 @@ def order_interfaces(queryset, sql_col, primary_ordering=tuple()):
|
|||||||
}).order_by(*ordering)
|
}).order_by(*ordering)
|
||||||
|
|
||||||
|
|
||||||
|
class SiteManager(NaturalOrderByManager):
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.natural_order_by('name')
|
||||||
|
|
||||||
|
|
||||||
class Site(CreatedUpdatedModel):
|
class Site(CreatedUpdatedModel):
|
||||||
"""
|
"""
|
||||||
A Site represents a geographic location within a network; typically a building or campus. The optional facility
|
A Site represents a geographic location within a network; typically a building or campus. The optional facility
|
||||||
@ -150,6 +158,8 @@ class Site(CreatedUpdatedModel):
|
|||||||
shipping_address = models.CharField(max_length=200, blank=True)
|
shipping_address = models.CharField(max_length=200, blank=True)
|
||||||
comments = models.TextField(blank=True)
|
comments = models.TextField(blank=True)
|
||||||
|
|
||||||
|
objects = SiteManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
|
||||||
@ -212,6 +222,12 @@ class RackGroup(models.Model):
|
|||||||
return "{}?group_id={}".format(reverse('dcim:rack_list'), self.pk)
|
return "{}?group_id={}".format(reverse('dcim:rack_list'), self.pk)
|
||||||
|
|
||||||
|
|
||||||
|
class RackManager(NaturalOrderByManager):
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.natural_order_by('site__name', 'name')
|
||||||
|
|
||||||
|
|
||||||
class Rack(CreatedUpdatedModel):
|
class Rack(CreatedUpdatedModel):
|
||||||
"""
|
"""
|
||||||
Devices are housed within Racks. Each rack has a defined height measured in rack units, and a front and rear face.
|
Devices are housed within Racks. Each rack has a defined height measured in rack units, and a front and rear face.
|
||||||
@ -224,6 +240,8 @@ class Rack(CreatedUpdatedModel):
|
|||||||
u_height = models.PositiveSmallIntegerField(default=42, verbose_name='Height (U)')
|
u_height = models.PositiveSmallIntegerField(default=42, verbose_name='Height (U)')
|
||||||
comments = models.TextField(blank=True)
|
comments = models.TextField(blank=True)
|
||||||
|
|
||||||
|
objects = RackManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['site', 'name']
|
ordering = ['site', 'name']
|
||||||
unique_together = [
|
unique_together = [
|
||||||
@ -583,6 +601,12 @@ class Platform(models.Model):
|
|||||||
return "{}?platform={}".format(reverse('dcim:device_list'), self.slug)
|
return "{}?platform={}".format(reverse('dcim:device_list'), self.slug)
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceManager(NaturalOrderByManager):
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.natural_order_by('name')
|
||||||
|
|
||||||
|
|
||||||
class Device(CreatedUpdatedModel):
|
class Device(CreatedUpdatedModel):
|
||||||
"""
|
"""
|
||||||
A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType,
|
A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType,
|
||||||
@ -612,6 +636,8 @@ class Device(CreatedUpdatedModel):
|
|||||||
blank=True, null=True, verbose_name='Primary IPv6')
|
blank=True, null=True, verbose_name='Primary IPv6')
|
||||||
comments = models.TextField(blank=True)
|
comments = models.TextField(blank=True)
|
||||||
|
|
||||||
|
objects = DeviceManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
unique_together = ['rack', 'position', 'face']
|
unique_together = ['rack', 'position', 'face']
|
||||||
|
@ -144,7 +144,7 @@ class RackGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RackListView(ObjectListView):
|
class RackListView(ObjectListView):
|
||||||
queryset = Rack.objects.select_related('site').annotate(device_count=Count('devices', distinct=True))
|
queryset = Rack.objects.select_related('site', 'group').annotate(device_count=Count('devices', distinct=True))
|
||||||
filter = filters.RackFilter
|
filter = filters.RackFilter
|
||||||
filter_form = forms.RackFilterForm
|
filter_form = forms.RackFilterForm
|
||||||
table = tables.RackTable
|
table = tables.RackTable
|
||||||
|
30
netbox/utilities/managers.py
Normal file
30
netbox/utilities/managers.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from django.db.models import Manager
|
||||||
|
|
||||||
|
|
||||||
|
class NaturalOrderByManager(Manager):
|
||||||
|
|
||||||
|
def natural_order_by(self, *fields):
|
||||||
|
"""
|
||||||
|
Attempt to order records naturally by segmenting a field into three parts:
|
||||||
|
|
||||||
|
1. Leading integer (if any)
|
||||||
|
2. Middle portion
|
||||||
|
3. Trailing integer (if any)
|
||||||
|
|
||||||
|
: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]
|
||||||
|
|
||||||
|
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+)') AS integer)".format(db_table, primary_field),
|
||||||
|
id2: "SUBSTRING({}.{} FROM '^\d*(.*?)\d*$')".format(db_table, primary_field),
|
||||||
|
id3: "CAST(SUBSTRING({}.{} FROM '(\d+)$') AS integer)".format(db_table, primary_field),
|
||||||
|
})
|
||||||
|
ordering = fields[0:-1] + (id1, id2, id3)
|
||||||
|
|
||||||
|
return queryset.order_by(*ordering)
|
Loading…
Reference in New Issue
Block a user