From ac72e90dcc000e8ae23c65e18b7452b96eeaa92b Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 5 Jan 2017 16:12:07 -0500 Subject: [PATCH] Fixes #778: Refactored order_interfaces() to fix InterfaceTemplate ordering within a table --- netbox/dcim/models.py | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index c95bca426..790128340 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -182,7 +182,7 @@ RPC_CLIENT_CHOICES = [ ] -def order_interfaces(queryset, sql_col, primary_ordering=tuple()): +def order_interfaces(queryset): """ Attempt to match interface names by their slot/position identifiers and order according. Matching is done using the following pattern: @@ -190,8 +190,8 @@ def order_interfaces(queryset, sql_col, primary_ordering=tuple()): {a}/{b}/{c}:{d} Interfaces are ordered first by field a, then b, then c, and finally d. Leading text (which typically indicates the - interface's type) is ignored. If any fields are not contained by an interface name, those fields are treated as - None. 'None' is ordered after all other values. For example: + interface's type) is then used to order any duplicate slot/position tuples. If any fields are not contained by an + interface name, those fields are treated as null. Null values are ordered after all other values. For example: et-0/0/0 et-0/0/1 @@ -210,12 +210,9 @@ def order_interfaces(queryset, sql_col, primary_ordering=tuple()): ... vlan1 vlan10 - - :param queryset: The base queryset to be ordered - :param sql_col: Table and name of the SQL column which contains the interface name (ex: ''dcim_interface.name') - :param primary_ordering: A tuple of fields which take ordering precedence before the interface name (optional) """ - ordering = primary_ordering + ('_id1', '_id2', '_id3', '_id4') + sql_col = '{}.name'.format(queryset.model._meta.db_table) + ordering = ('_id1', '_id2', '_id3', '_id4', 'name') return queryset.extra(select={ '_id1': "CAST(SUBSTRING({} FROM '([0-9]+)\/[0-9]+\/[0-9]+(:[0-9]+)?$') AS integer)".format(sql_col), '_id2': "CAST(SUBSTRING({} FROM '([0-9]+)\/[0-9]+(:[0-9]+)?$') AS integer)".format(sql_col), @@ -701,11 +698,17 @@ class PowerOutletTemplate(models.Model): return self.name -class InterfaceTemplateManager(models.Manager): +class InterfaceManager(models.Manager): def get_queryset(self): - qs = super(InterfaceTemplateManager, self).get_queryset() - return order_interfaces(qs, 'dcim_interfacetemplate.name', ('device_type',)) + qs = super(InterfaceManager, self).get_queryset() + return order_interfaces(qs) + + def virtual(self): + return self.get_queryset().filter(form_factor=IFACE_FF_VIRTUAL) + + def physical(self): + return self.get_queryset().exclude(form_factor=IFACE_FF_VIRTUAL) class InterfaceTemplate(models.Model): @@ -717,7 +720,7 @@ class InterfaceTemplate(models.Model): form_factor = models.PositiveSmallIntegerField(choices=IFACE_FF_CHOICES, default=IFACE_FF_10GE_SFP_PLUS) mgmt_only = models.BooleanField(default=False, verbose_name='Management only') - objects = InterfaceTemplateManager() + objects = InterfaceManager() class Meta: ordering = ['device_type', 'name'] @@ -1094,19 +1097,6 @@ class PowerOutlet(models.Model): return self.device.get_absolute_url() -class InterfaceManager(models.Manager): - - def get_queryset(self): - qs = super(InterfaceManager, self).get_queryset() - return order_interfaces(qs, 'dcim_interface.name', ('device',)) - - def virtual(self): - return self.get_queryset().filter(form_factor=IFACE_FF_VIRTUAL) - - def physical(self): - return self.get_queryset().exclude(form_factor=IFACE_FF_VIRTUAL) - - class Interface(models.Model): """ A physical data interface within a Device. An Interface can connect to exactly one other Interface via the creation