mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 01:41:22 -06:00
Implemented DeviceComponentManager; removed natsort as a dependency
This commit is contained in:
parent
6140dd955a
commit
60452a7b0c
@ -12,7 +12,6 @@ drf-yasg[validation]
|
|||||||
graphviz
|
graphviz
|
||||||
# py-gfm requires Markdown<3.0
|
# py-gfm requires Markdown<3.0
|
||||||
Markdown<3.0
|
Markdown<3.0
|
||||||
natsort
|
|
||||||
netaddr
|
netaddr
|
||||||
Pillow
|
Pillow
|
||||||
psycopg2-binary
|
psycopg2-binary
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import re
|
import re
|
||||||
from operator import attrgetter
|
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@ -8,7 +7,6 @@ from django.contrib.postgres.forms.array import SimpleArrayField
|
|||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import Count, Q
|
from django.db.models import Count, Q
|
||||||
from mptt.forms import TreeNodeChoiceField
|
from mptt.forms import TreeNodeChoiceField
|
||||||
from natsort import natsorted
|
|
||||||
from taggit.forms import TagField
|
from taggit.forms import TagField
|
||||||
from timezone_field import TimeZoneFormField
|
from timezone_field import TimeZoneFormField
|
||||||
|
|
||||||
@ -803,7 +801,7 @@ class FrontPortTemplateCreateForm(ComponentForm):
|
|||||||
|
|
||||||
# Populate rear port choices
|
# Populate rear port choices
|
||||||
choices = []
|
choices = []
|
||||||
rear_ports = natsorted(RearPortTemplate.objects.filter(device_type=self.parent), key=attrgetter('name'))
|
rear_ports = RearPortTemplate.objects.filter(device_type=self.parent)
|
||||||
for rear_port in rear_ports:
|
for rear_port in rear_ports:
|
||||||
for i in range(1, rear_port.positions + 1):
|
for i in range(1, rear_port.positions + 1):
|
||||||
if (rear_port.pk, i) not in occupied_port_positions:
|
if (rear_port.pk, i) not in occupied_port_positions:
|
||||||
@ -1687,7 +1685,7 @@ class FrontPortCreateForm(ComponentForm):
|
|||||||
|
|
||||||
# Populate rear port choices
|
# Populate rear port choices
|
||||||
choices = []
|
choices = []
|
||||||
rear_ports = natsorted(RearPort.objects.filter(device=self.parent), key=attrgetter('name'))
|
rear_ports = RearPort.objects.filter(device=self.parent)
|
||||||
for rear_port in rear_ports:
|
for rear_port in rear_ports:
|
||||||
for i in range(1, rear_port.positions + 1):
|
for i in range(1, rear_port.positions + 1):
|
||||||
if (rear_port.pk, i) not in occupied_port_positions:
|
if (rear_port.pk, i) not in occupied_port_positions:
|
||||||
|
@ -3,6 +3,7 @@ from django.db.models.expressions import RawSQL
|
|||||||
|
|
||||||
from .constants import NONCONNECTABLE_IFACE_TYPES
|
from .constants import NONCONNECTABLE_IFACE_TYPES
|
||||||
|
|
||||||
|
# Regular expressions for parsing Interface names
|
||||||
TYPE_RE = r"SUBSTRING({} FROM '^([^0-9\.:]+)')"
|
TYPE_RE = r"SUBSTRING({} FROM '^([^0-9\.:]+)')"
|
||||||
SLOT_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^(?:[^0-9]+)?(\d{{1,9}})/') AS integer), NULL)"
|
SLOT_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^(?:[^0-9]+)?(\d{{1,9}})/') AS integer), NULL)"
|
||||||
SUBSLOT_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^(?:[^0-9\.:]+)?\d{{1,9}}/(\d{{1,9}})') AS integer), NULL)"
|
SUBSLOT_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^(?:[^0-9\.:]+)?\d{{1,9}}/(\d{{1,9}})') AS integer), NULL)"
|
||||||
@ -13,6 +14,22 @@ CHANNEL_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^.*:(\d{{1,9}})(\.\d{{1,9}})?$')
|
|||||||
VC_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^.*\.(\d{{1,9}})$') AS integer), 0)"
|
VC_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^.*\.(\d{{1,9}})$') AS integer), 0)"
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceComponentManager(Manager):
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
|
||||||
|
queryset = super(DeviceComponentManager, self).get_queryset()
|
||||||
|
table_name = self.model._meta.db_table
|
||||||
|
sql = r"CONCAT(REGEXP_REPLACE({}.name, '\d+$', ''), LPAD(SUBSTRING({}.name FROM '\d+$'), 8, '0'))"
|
||||||
|
|
||||||
|
# Pad any trailing digits to effect natural sorting
|
||||||
|
return queryset.extra(
|
||||||
|
select={
|
||||||
|
'name_padded': sql.format(table_name, table_name),
|
||||||
|
}
|
||||||
|
).order_by('name_padded')
|
||||||
|
|
||||||
|
|
||||||
class InterfaceQuerySet(QuerySet):
|
class InterfaceQuerySet(QuerySet):
|
||||||
|
|
||||||
def connectable(self):
|
def connectable(self):
|
@ -22,7 +22,7 @@ from utilities.models import ChangeLoggedModel
|
|||||||
from utilities.utils import serialize_object, to_meters
|
from utilities.utils import serialize_object, to_meters
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .fields import ASNField, MACAddressField
|
from .fields import ASNField, MACAddressField
|
||||||
from .querysets import InterfaceManager
|
from .managers import DeviceComponentManager, InterfaceManager
|
||||||
|
|
||||||
|
|
||||||
class ComponentTemplateModel(models.Model):
|
class ComponentTemplateModel(models.Model):
|
||||||
@ -965,6 +965,8 @@ class ConsolePortTemplate(ComponentTemplateModel):
|
|||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
unique_together = ['device_type', 'name']
|
unique_together = ['device_type', 'name']
|
||||||
@ -986,6 +988,8 @@ class ConsoleServerPortTemplate(ComponentTemplateModel):
|
|||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
unique_together = ['device_type', 'name']
|
unique_together = ['device_type', 'name']
|
||||||
@ -1007,6 +1011,8 @@ class PowerPortTemplate(ComponentTemplateModel):
|
|||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
unique_together = ['device_type', 'name']
|
unique_together = ['device_type', 'name']
|
||||||
@ -1028,6 +1034,8 @@ class PowerOutletTemplate(ComponentTemplateModel):
|
|||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
unique_together = ['device_type', 'name']
|
unique_together = ['device_type', 'name']
|
||||||
@ -1057,7 +1065,7 @@ class InterfaceTemplate(ComponentTemplateModel):
|
|||||||
verbose_name='Management only'
|
verbose_name='Management only'
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = InterfaceManager
|
objects = InterfaceManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
@ -1092,6 +1100,8 @@ class FrontPortTemplate(ComponentTemplateModel):
|
|||||||
validators=[MinValueValidator(1), MaxValueValidator(64)]
|
validators=[MinValueValidator(1), MaxValueValidator(64)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
unique_together = [
|
unique_together = [
|
||||||
@ -1139,6 +1149,8 @@ class RearPortTemplate(ComponentTemplateModel):
|
|||||||
validators=[MinValueValidator(1), MaxValueValidator(64)]
|
validators=[MinValueValidator(1), MaxValueValidator(64)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
unique_together = ['device_type', 'name']
|
unique_together = ['device_type', 'name']
|
||||||
@ -1160,6 +1172,8 @@ class DeviceBayTemplate(ComponentTemplateModel):
|
|||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['device_type', 'name']
|
ordering = ['device_type', 'name']
|
||||||
unique_together = ['device_type', 'name']
|
unique_together = ['device_type', 'name']
|
||||||
@ -1693,6 +1707,7 @@ class ConsolePort(CableTermination, ComponentModel):
|
|||||||
default=CONNECTION_STATUS_CONNECTED
|
default=CONNECTION_STATUS_CONNECTED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
tags = TaggableManager()
|
tags = TaggableManager()
|
||||||
|
|
||||||
csv_headers = ['console_server', 'connected_endpoint', 'device', 'console_port', 'connection_status']
|
csv_headers = ['console_server', 'connected_endpoint', 'device', 'console_port', 'connection_status']
|
||||||
@ -1721,16 +1736,6 @@ class ConsolePort(CableTermination, ComponentModel):
|
|||||||
# Console server ports
|
# Console server ports
|
||||||
#
|
#
|
||||||
|
|
||||||
class ConsoleServerPortManager(models.Manager):
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# Pad any trailing digits to effect natural sorting
|
|
||||||
return super(ConsoleServerPortManager, self).get_queryset().extra(select={
|
|
||||||
'name_padded': r"CONCAT(REGEXP_REPLACE(dcim_consoleserverport.name, '\d+$', ''), "
|
|
||||||
r"LPAD(SUBSTRING(dcim_consoleserverport.name FROM '\d+$'), 8, '0'))",
|
|
||||||
}).order_by('device', 'name_padded')
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPort(CableTermination, ComponentModel):
|
class ConsoleServerPort(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A physical port within a Device (typically a designated console server) which provides access to ConsolePorts.
|
A physical port within a Device (typically a designated console server) which provides access to ConsolePorts.
|
||||||
@ -1744,7 +1749,7 @@ class ConsoleServerPort(CableTermination, ComponentModel):
|
|||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = ConsoleServerPortManager()
|
objects = DeviceComponentManager()
|
||||||
tags = TaggableManager()
|
tags = TaggableManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -1785,6 +1790,7 @@ class PowerPort(CableTermination, ComponentModel):
|
|||||||
default=CONNECTION_STATUS_CONNECTED
|
default=CONNECTION_STATUS_CONNECTED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
tags = TaggableManager()
|
tags = TaggableManager()
|
||||||
|
|
||||||
csv_headers = ['pdu', 'connected_endpoint', 'device', 'power_port', 'connection_status']
|
csv_headers = ['pdu', 'connected_endpoint', 'device', 'power_port', 'connection_status']
|
||||||
@ -1813,16 +1819,6 @@ class PowerPort(CableTermination, ComponentModel):
|
|||||||
# Power outlets
|
# Power outlets
|
||||||
#
|
#
|
||||||
|
|
||||||
class PowerOutletManager(models.Manager):
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
# Pad any trailing digits to effect natural sorting
|
|
||||||
return super(PowerOutletManager, self).get_queryset().extra(select={
|
|
||||||
'name_padded': r"CONCAT(REGEXP_REPLACE(dcim_poweroutlet.name, '\d+$', ''), "
|
|
||||||
r"LPAD(SUBSTRING(dcim_poweroutlet.name FROM '\d+$'), 8, '0'))",
|
|
||||||
}).order_by('device', 'name_padded')
|
|
||||||
|
|
||||||
|
|
||||||
class PowerOutlet(CableTermination, ComponentModel):
|
class PowerOutlet(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A physical power outlet (output) within a Device which provides power to a PowerPort.
|
A physical power outlet (output) within a Device which provides power to a PowerPort.
|
||||||
@ -1836,7 +1832,7 @@ class PowerOutlet(CableTermination, ComponentModel):
|
|||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = PowerOutletManager()
|
objects = DeviceComponentManager()
|
||||||
tags = TaggableManager()
|
tags = TaggableManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -2125,6 +2121,7 @@ class FrontPort(CableTermination, ComponentModel):
|
|||||||
validators=[MinValueValidator(1), MaxValueValidator(64)]
|
validators=[MinValueValidator(1), MaxValueValidator(64)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
tags = TaggableManager()
|
tags = TaggableManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -2174,6 +2171,7 @@ class RearPort(CableTermination, ComponentModel):
|
|||||||
validators=[MinValueValidator(1), MaxValueValidator(64)]
|
validators=[MinValueValidator(1), MaxValueValidator(64)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
tags = TaggableManager()
|
tags = TaggableManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -2209,6 +2207,7 @@ class DeviceBay(ComponentModel):
|
|||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = DeviceComponentManager()
|
||||||
tags = TaggableManager()
|
tags = TaggableManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from operator import attrgetter
|
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.core.paginator import EmptyPage, PageNotAnInteger
|
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||||
@ -11,7 +9,6 @@ from django.urls import reverse
|
|||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
from natsort import natsorted
|
|
||||||
|
|
||||||
from circuits.models import Circuit
|
from circuits.models import Circuit
|
||||||
from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
|
from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
|
||||||
@ -535,19 +532,19 @@ class DeviceTypeView(View):
|
|||||||
|
|
||||||
# Component tables
|
# Component tables
|
||||||
consoleport_table = tables.ConsolePortTemplateTable(
|
consoleport_table = tables.ConsolePortTemplateTable(
|
||||||
natsorted(ConsolePortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')),
|
ConsolePortTemplate.objects.filter(device_type=devicetype),
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
consoleserverport_table = tables.ConsoleServerPortTemplateTable(
|
consoleserverport_table = tables.ConsoleServerPortTemplateTable(
|
||||||
natsorted(ConsoleServerPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')),
|
ConsoleServerPortTemplate.objects.filter(device_type=devicetype),
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
powerport_table = tables.PowerPortTemplateTable(
|
powerport_table = tables.PowerPortTemplateTable(
|
||||||
natsorted(PowerPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')),
|
PowerPortTemplate.objects.filter(device_type=devicetype),
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
poweroutlet_table = tables.PowerOutletTemplateTable(
|
poweroutlet_table = tables.PowerOutletTemplateTable(
|
||||||
natsorted(PowerOutletTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')),
|
PowerOutletTemplate.objects.filter(device_type=devicetype),
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
interface_table = tables.InterfaceTemplateTable(
|
interface_table = tables.InterfaceTemplateTable(
|
||||||
@ -555,15 +552,15 @@ class DeviceTypeView(View):
|
|||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
front_port_table = tables.FrontPortTemplateTable(
|
front_port_table = tables.FrontPortTemplateTable(
|
||||||
natsorted(FrontPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')),
|
FrontPortTemplate.objects.filter(device_type=devicetype),
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
rear_port_table = tables.RearPortTemplateTable(
|
rear_port_table = tables.RearPortTemplateTable(
|
||||||
natsorted(RearPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')),
|
RearPortTemplate.objects.filter(device_type=devicetype),
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
devicebay_table = tables.DeviceBayTemplateTable(
|
devicebay_table = tables.DeviceBayTemplateTable(
|
||||||
natsorted(DeviceBayTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')),
|
DeviceBayTemplate.objects.filter(device_type=devicetype),
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
if request.user.has_perm('dcim.change_devicetype'):
|
if request.user.has_perm('dcim.change_devicetype'):
|
||||||
@ -880,19 +877,13 @@ class DeviceView(View):
|
|||||||
vc_members = []
|
vc_members = []
|
||||||
|
|
||||||
# Console ports
|
# Console ports
|
||||||
console_ports = natsorted(
|
console_ports = device.consoleports.select_related('connected_endpoint__device', 'cable')
|
||||||
device.consoleports.select_related('connected_endpoint__device', 'cable'),
|
|
||||||
key=attrgetter('name')
|
|
||||||
)
|
|
||||||
|
|
||||||
# Console server ports
|
# Console server ports
|
||||||
consoleserverports = device.consoleserverports.select_related('connected_endpoint__device', 'cable')
|
consoleserverports = device.consoleserverports.select_related('connected_endpoint__device', 'cable')
|
||||||
|
|
||||||
# Power ports
|
# Power ports
|
||||||
power_ports = natsorted(
|
power_ports = device.powerports.select_related('connected_endpoint__device', 'cable')
|
||||||
device.powerports.select_related('connected_endpoint__device', 'cable'),
|
|
||||||
key=attrgetter('name')
|
|
||||||
)
|
|
||||||
|
|
||||||
# Power outlets
|
# Power outlets
|
||||||
poweroutlets = device.poweroutlets.select_related('connected_endpoint__device', 'cable')
|
poweroutlets = device.poweroutlets.select_related('connected_endpoint__device', 'cable')
|
||||||
@ -911,10 +902,7 @@ class DeviceView(View):
|
|||||||
rear_ports = device.rearports.select_related('cable')
|
rear_ports = device.rearports.select_related('cable')
|
||||||
|
|
||||||
# Device bays
|
# Device bays
|
||||||
device_bays = natsorted(
|
device_bays = device.device_bays.select_related('installed_device__device_type__manufacturer')
|
||||||
device.device_bays.select_related('installed_device__device_type__manufacturer'),
|
|
||||||
key=attrgetter('name')
|
|
||||||
)
|
|
||||||
|
|
||||||
# Services
|
# Services
|
||||||
services = device.services.all()
|
services = device.services.all()
|
||||||
|
@ -11,7 +11,6 @@ djangorestframework==3.9.0
|
|||||||
drf-yasg[validation]==1.11.0
|
drf-yasg[validation]==1.11.0
|
||||||
graphviz==0.10.1
|
graphviz==0.10.1
|
||||||
Markdown==2.6.11
|
Markdown==2.6.11
|
||||||
natsort==5.4.1
|
|
||||||
netaddr==0.7.19
|
netaddr==0.7.19
|
||||||
Pillow==5.3.0
|
Pillow==5.3.0
|
||||||
psycopg2-binary==2.7.5
|
psycopg2-binary==2.7.5
|
||||||
|
Loading…
Reference in New Issue
Block a user