mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Fixes #1079: Order interfaces naturally via API
This commit is contained in:
@ -433,12 +433,12 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
|
|
||||||
|
|
||||||
class DeviceComponentFilterSet(django_filters.FilterSet):
|
class DeviceComponentFilterSet(django_filters.FilterSet):
|
||||||
device_id = django_filters.ModelMultipleChoiceFilter(
|
device_id = django_filters.ModelChoiceFilter(
|
||||||
name='device',
|
name='device',
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
label='Device (ID)',
|
label='Device (ID)',
|
||||||
)
|
)
|
||||||
device = django_filters.ModelMultipleChoiceFilter(
|
device = django_filters.ModelChoiceFilter(
|
||||||
name='device__name',
|
name='device__name',
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
@ -474,7 +474,17 @@ class PowerOutletFilter(DeviceComponentFilterSet):
|
|||||||
fields = ['name']
|
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(
|
type = django_filters.CharFilter(
|
||||||
method='filter_type',
|
method='filter_type',
|
||||||
label='Interface type',
|
label='Interface type',
|
||||||
@ -493,6 +503,14 @@ class InterfaceFilter(DeviceComponentFilterSet):
|
|||||||
model = Interface
|
model = Interface
|
||||||
fields = ['name', 'form_factor']
|
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):
|
def filter_type(self, queryset, name, value):
|
||||||
value = value.strip().lower()
|
value = value.strip().lower()
|
||||||
if value == 'physical':
|
if value == 'physical':
|
||||||
|
@ -816,7 +816,7 @@ class PowerOutletTemplate(models.Model):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class InterfaceManager(models.Manager):
|
class InterfaceQuerySet(models.QuerySet):
|
||||||
|
|
||||||
def order_naturally(self, method=IFACE_ORDERING_POSITION):
|
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 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.
|
the prescribed fields.
|
||||||
"""
|
"""
|
||||||
queryset = self.get_queryset()
|
sql_col = '{}.name'.format(self.model._meta.db_table)
|
||||||
sql_col = '{}.name'.format(queryset.model._meta.db_table)
|
|
||||||
ordering = {
|
ordering = {
|
||||||
IFACE_ORDERING_POSITION: ('_slot', '_subslot', '_position', '_channel', '_vc', '_type', 'name'),
|
IFACE_ORDERING_POSITION: ('_slot', '_subslot', '_position', '_channel', '_vc', '_type', 'name'),
|
||||||
IFACE_ORDERING_NAME: ('_type', '_slot', '_subslot', '_position', '_channel', '_vc', 'name'),
|
IFACE_ORDERING_NAME: ('_type', '_slot', '_subslot', '_position', '_channel', '_vc', 'name'),
|
||||||
}[method]
|
}[method]
|
||||||
return queryset.extra(select={
|
return self.extra(select={
|
||||||
'_type': "SUBSTRING({} FROM '^([^0-9]+)')".format(sql_col),
|
'_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),
|
'_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),
|
'_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)
|
form_factor = models.PositiveSmallIntegerField(choices=IFACE_FF_CHOICES, default=IFACE_FF_10GE_SFP_PLUS)
|
||||||
mgmt_only = models.BooleanField(default=False, verbose_name='Management only')
|
mgmt_only = models.BooleanField(default=False, verbose_name='Management only')
|
||||||
|
|
||||||
objects = InterfaceManager()
|
objects = InterfaceQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
@ -1317,7 +1316,7 @@ class Interface(models.Model):
|
|||||||
help_text="This interface is used only for out-of-band management")
|
help_text="This interface is used only for out-of-band management")
|
||||||
description = models.CharField(max_length=100, blank=True)
|
description = models.CharField(max_length=100, blank=True)
|
||||||
|
|
||||||
objects = InterfaceManager()
|
objects = InterfaceQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device', 'name']
|
ordering = ['device', 'name']
|
||||||
|
Reference in New Issue
Block a user