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

Fixes #4336: Ensure interfaces without a subinterface ID are ordered before subinterface zero

This commit is contained in:
Jeremy Stretch
2020-04-21 16:13:34 -04:00
parent ada55dfdfb
commit 131d2c97ca
7 changed files with 56 additions and 18 deletions

View File

@ -10,6 +10,7 @@
* [#2994](https://github.com/netbox-community/netbox/issues/2994) - Prevent modifying termination points of existing cable to ensure end-to-end path integrity
* [#3356](https://github.com/netbox-community/netbox/issues/3356) - Correct Swagger schema specification for the available prefixes/IPs API endpoints
* [#4336](https://github.com/netbox-community/netbox/issues/4336) - Ensure interfaces without a subinterface ID are ordered before subinterface zero
* [#4361](https://github.com/netbox-community/netbox/issues/4361) - Fix Type of `connection_state` in Swagger schema
* [#4388](https://github.com/netbox-community/netbox/issues/4388) - Fix detection of connected endpoints when connecting rear ports
* [#4489](https://github.com/netbox-community/netbox/issues/4489) - Fix display of parent/child role on device type view

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.5 on 2020-04-21 20:13
from django.db import migrations
import utilities.query_functions
class Migration(migrations.Migration):
dependencies = [
('dcim', '0104_correct_infiniband_types'),
]
operations = [
migrations.AlterModelOptions(
name='interface',
options={'ordering': ('device', utilities.query_functions.CollateAsChar('_name'))},
),
]

View File

@ -16,6 +16,7 @@ from extras.models import ObjectChange, TaggedItem
from extras.utils import extras_features
from utilities.fields import NaturalOrderingField
from utilities.ordering import naturalize_interface
from utilities.query_functions import CollateAsChar
from utilities.utils import serialize_object
from virtualization.choices import VMInterfaceTypeChoices
@ -676,7 +677,7 @@ class Interface(CableTermination, ComponentModel):
class Meta:
# TODO: ordering and unique_together should include virtual_machine
ordering = ('device', '_name')
ordering = ('device', CollateAsChar('_name'))
unique_together = ('device', 'name')
def __str__(self):

View File

@ -23,28 +23,34 @@ class NaturalOrderingTestCase(TestCase):
INTERFACES = [
'0',
'0.0',
'0.1',
'0.2',
'0.10',
'0.100',
'0:1',
'0:1.0',
'0:1.1',
'0:1.2',
'0:1.10',
'0:2',
'0:2.0',
'0:2.1',
'0:2.2',
'0:2.10',
'1',
'1.0',
'1.1',
'1.2',
'1.10',
'1.100',
'1:1',
'1:1.0',
'1:1.1',
'1:1.2',
'1:1.10',
'1:2',
'1:2.0',
'1:2.1',
'1:2.2',
'1:2.10',

View File

@ -75,7 +75,7 @@ def naturalize_interface(value, max_length):
if part is not None:
output += part.rjust(6, '0')
else:
output += '000000'
output += '......'
# Finally, naturalize any remaining text and append it
if match.group('remainder') is not None and len(output) < max_length:

View File

@ -0,0 +1,9 @@
from django.db.models import F, Func
class CollateAsChar(Func):
"""
Disregard localization by collating a field as a plain character string. Helpful for ensuring predictable ordering.
"""
function = 'C'
template = '(%(expressions)s) COLLATE "%(function)s"'

View File

@ -30,29 +30,32 @@ class NaturalizationTestCase(TestCase):
# Original, naturalized
data = (
# IOS/JunOS-style
('Gi', '9999999999999999Gi000000000000000000'),
('Gi1', '9999999999999999Gi000001000000000000'),
('Gi1.0', '9999999999999999Gi000001000000000000'),
('Gi1.1', '9999999999999999Gi000001000000000001'),
('Gi1:0', '9999999999999999Gi000001000000000000'),
('Gi', '9999999999999999Gi..................'),
('Gi1', '9999999999999999Gi000001............'),
('Gi1.0', '9999999999999999Gi000001......000000'),
('Gi1.1', '9999999999999999Gi000001......000001'),
('Gi1:0', '9999999999999999Gi000001000000......'),
('Gi1:0.0', '9999999999999999Gi000001000000000000'),
('Gi1:0.1', '9999999999999999Gi000001000000000001'),
('Gi1:1', '9999999999999999Gi000001000001000000'),
('Gi1:1', '9999999999999999Gi000001000001......'),
('Gi1:1.0', '9999999999999999Gi000001000001000000'),
('Gi1:1.1', '9999999999999999Gi000001000001000001'),
('Gi1/2', '0001999999999999Gi000002000000000000'),
('Gi1/2/3', '0001000299999999Gi000003000000000000'),
('Gi1/2/3/4', '0001000200039999Gi000004000000000000'),
('Gi1/2/3/4/5', '0001000200030004Gi000005000000000000'),
('Gi1/2/3/4/5:6', '0001000200030004Gi000005000006000000'),
('Gi1/2', '0001999999999999Gi000002............'),
('Gi1/2/3', '0001000299999999Gi000003............'),
('Gi1/2/3/4', '0001000200039999Gi000004............'),
('Gi1/2/3/4/5', '0001000200030004Gi000005............'),
('Gi1/2/3/4/5:6', '0001000200030004Gi000005000006......'),
('Gi1/2/3/4/5:6.7', '0001000200030004Gi000005000006000007'),
# Generic
('Interface 1', '9999999999999999Interface 000001000000000000'),
('Interface 1 (other)', '9999999999999999Interface 000001000000000000 (other)'),
('Interface 99', '9999999999999999Interface 000099000000000000'),
('PCIe1-p1', '9999999999999999PCIe000001000000000000-p00000001'),
('PCIe1-p99', '9999999999999999PCIe000001000000000000-p00000099'),
('Interface 1', '9999999999999999Interface 000001............'),
('Interface 1 (other)', '9999999999999999Interface 000001............ (other)'),
('Interface 99', '9999999999999999Interface 000099............'),
('PCIe1-p1', '9999999999999999PCIe000001............-p00000001'),
('PCIe1-p99', '9999999999999999PCIe000001............-p00000099'),
)
for origin, naturalized in data: