From cd263484c351bdd09fe36b56ff05e820eb03fa03 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 14 Jun 2017 14:34:14 -0400 Subject: [PATCH] Fixes #1079: Order interfaces naturally via API --- netbox/dcim/filters.py | 24 +++++++++++++++++++++--- netbox/dcim/models.py | 11 +++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 93a325d98..e418d169d 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -433,12 +433,12 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet): class DeviceComponentFilterSet(django_filters.FilterSet): - device_id = django_filters.ModelMultipleChoiceFilter( + device_id = django_filters.ModelChoiceFilter( name='device', queryset=Device.objects.all(), label='Device (ID)', ) - device = django_filters.ModelMultipleChoiceFilter( + device = django_filters.ModelChoiceFilter( name='device__name', queryset=Device.objects.all(), to_field_name='name', @@ -474,7 +474,17 @@ class PowerOutletFilter(DeviceComponentFilterSet): fields = ['name'] -class InterfaceFilter(DeviceComponentFilterSet): +class InterfaceFilter(django_filters.FilterSet): + device = django_filters.CharFilter( + method='filter_device', + name='name', + label='Device', + ) + device_id = django_filters.NumberFilter( + method='filter_device', + name='pk', + label='Device (ID)', + ) type = django_filters.CharFilter( method='filter_type', label='Interface type', @@ -493,6 +503,14 @@ class InterfaceFilter(DeviceComponentFilterSet): model = Interface fields = ['name', 'form_factor'] + def filter_device(self, queryset, name, value): + try: + device = Device.objects.select_related('device_type').get(**{name: value}) + ordering = device.device_type.interface_ordering + return queryset.filter(device=device).order_naturally(ordering) + except Device.DoesNotExist: + return queryset.none() + def filter_type(self, queryset, name, value): value = value.strip().lower() if value == 'physical': diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 6411c6bff..dbfe95519 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -816,7 +816,7 @@ class PowerOutletTemplate(models.Model): return self.name -class InterfaceManager(models.Manager): +class InterfaceQuerySet(models.QuerySet): def order_naturally(self, method=IFACE_ORDERING_POSITION): """ @@ -841,13 +841,12 @@ class InterfaceManager(models.Manager): The original `name` field is taken as a whole to serve as a fallback in the event interfaces do not match any of the prescribed fields. """ - queryset = self.get_queryset() - sql_col = '{}.name'.format(queryset.model._meta.db_table) + sql_col = '{}.name'.format(self.model._meta.db_table) ordering = { IFACE_ORDERING_POSITION: ('_slot', '_subslot', '_position', '_channel', '_vc', '_type', 'name'), IFACE_ORDERING_NAME: ('_type', '_slot', '_subslot', '_position', '_channel', '_vc', 'name'), }[method] - return queryset.extra(select={ + return self.extra(select={ '_type': "SUBSTRING({} FROM '^([^0-9]+)')".format(sql_col), '_slot': "CAST(SUBSTRING({} FROM '([0-9]+)\/[0-9]+\/[0-9]+(:[0-9]+)?(\.[0-9]+)?$') AS integer)".format(sql_col), '_subslot': "CAST(SUBSTRING({} FROM '([0-9]+)\/[0-9]+(:[0-9]+)?(\.[0-9]+)?$') AS integer)".format(sql_col), @@ -867,7 +866,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 = InterfaceManager() + objects = InterfaceQuerySet.as_manager() class Meta: ordering = ['device_type', 'name'] @@ -1317,7 +1316,7 @@ class Interface(models.Model): help_text="This interface is used only for out-of-band management") description = models.CharField(max_length=100, blank=True) - objects = InterfaceManager() + objects = InterfaceQuerySet.as_manager() class Meta: ordering = ['device', 'name']