Implemented DeviceComponentManager; removed natsort as a dependency

This commit is contained in:
Jeremy Stretch 2018-11-06 12:43:30 -05:00
parent 6140dd955a
commit 60452a7b0c
6 changed files with 52 additions and 52 deletions

View File

@ -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

View File

@ -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:

View File

@ -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):

View File

@ -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:

View File

@ -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()

View File

@ -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