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

Added length and length_unit fields to Cable

This commit is contained in:
Jeremy Stretch
2018-10-26 10:28:25 -04:00
parent 2d90fc608e
commit 6bea8cc546
9 changed files with 97 additions and 8 deletions

View File

@ -317,3 +317,14 @@ COMPATIBLE_TERMINATION_TYPES = {
'frontport': ['consoleport', 'consoleserverport', 'interface', 'frontport', 'rearport'],
'rearport': ['consoleport', 'consoleserverport', 'interface', 'frontport', 'rearport'],
}
LENGTH_UNIT_METER = 'm'
LENGTH_UNIT_CENTIMETER = 'cm'
LENGTH_UNIT_FOOT = 'ft'
LENGTH_UNIT_INCH = 'in'
LENGTH_UNIT_CHOICES = (
(LENGTH_UNIT_METER, 'Meters'),
(LENGTH_UNIT_CENTIMETER, 'Centimeters'),
(LENGTH_UNIT_FOOT, 'Feet'),
(LENGTH_UNIT_INCH, 'Inches'),
)

View File

@ -786,10 +786,19 @@ class VirtualChassisFilter(django_filters.FilterSet):
class CableFilter(django_filters.FilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
class Meta:
model = Cable
fields = ['type', 'status', 'color']
fields = ['type', 'status', 'color', 'length', 'length_unit']
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(label__icontains=value)
class ConsoleConnectionFilter(django_filters.FilterSet):

View File

@ -2211,7 +2211,7 @@ class CableForm(BootstrapMixin, forms.ModelForm):
class Meta:
model = Cable
fields = ('type', 'status', 'label', 'color')
fields = ('type', 'status', 'label', 'color', 'length', 'length_unit')
class CableFilterForm(BootstrapMixin, forms.Form):

View File

@ -123,6 +123,9 @@ class Migration(migrations.Migration):
('status', models.BooleanField(default=True)),
('label', models.CharField(blank=True, max_length=100)),
('color', utilities.fields.ColorField(blank=True, max_length=6)),
('length', models.PositiveSmallIntegerField(blank=True, null=True)),
('length_unit', models.CharField(blank=True, max_length=2)),
('_abs_length', models.DecimalField(blank=True, decimal_places=4, max_digits=10, null=True)),
('termination_a_type', models.ForeignKey(limit_choices_to={'model__in': ['consoleport', 'consoleserverport', 'interface', 'poweroutlet', 'powerport', 'frontport', 'rearport']}, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.ContentType')),
('termination_b_type', models.ForeignKey(limit_choices_to={'model__in': ['consoleport', 'consoleserverport', 'interface', 'poweroutlet', 'powerport', 'frontport', 'rearport']}, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.ContentType')),
],

View File

@ -20,7 +20,7 @@ from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange
from utilities.fields import ColorField, NullableCharField
from utilities.managers import NaturalOrderByManager
from utilities.models import ChangeLoggedModel
from utilities.utils import serialize_object
from utilities.utils import serialize_object, to_meters
from .constants import *
from .fields import ASNField, MACAddressField
from .querysets import CableQuerySet, InterfaceQuerySet
@ -2366,6 +2366,22 @@ class Cable(ChangeLoggedModel):
color = ColorField(
blank=True
)
length = models.PositiveSmallIntegerField(
blank=True,
null=True
)
length_unit = models.CharField(
choices=LENGTH_UNIT_CHOICES,
max_length=2,
blank=True
)
# Stores the normalized length (in meters) for database ordering
_abs_length = models.DecimalField(
max_digits=10,
decimal_places=4,
blank=True,
null=True
)
objects = CableQuerySet.as_manager()
@ -2383,6 +2399,14 @@ class Cable(ChangeLoggedModel):
def get_absolute_url(self):
return reverse('dcim:cable', args=[self.pk])
def save(self, *args, **kwargs):
# Store the given length (if any) in meters for use in database ordering
if self.length and self.length_unit:
self._abs_length = to_meters(self.length, self.length_unit)
super(Cable, self).save(*args, **kwargs)
def get_path_endpoints(self):
"""
Traverse both ends of a cable path and return its connected endpoints. Note that one or both endpoints may be
@ -2412,13 +2436,13 @@ class Cable(ChangeLoggedModel):
return termination
# Find the cable (if any) attached to the peer port
next_cable, far_end = peer_port.get_connection()
next_cable = peer_port.get_connected_cable()
# If no cable exists, return None
if next_cable is None:
return None
# Return the far side termination of the cable
return trace_cable(far_end, position)
return trace_cable(next_cable.far_end, position)
return trace_cable(self.termination_a), trace_cable(self.termination_b)

View File

@ -170,6 +170,10 @@ VIRTUALCHASSIS_ACTIONS = """
{% endif %}
"""
CABLE_LENGTH = """
{% if record.length %}{{ record.length }}{{ record.length_unit }}{% else %}—{% endif %}
"""
#
# Regions
@ -626,6 +630,10 @@ class CableTable(BaseTable):
args=[Accessor('pk')],
verbose_name='PK'
)
label_ = tables.Column(
accessor=Accessor('label'),
verbose_name='Label'
)
device_a = tables.LinkColumn(
viewname='dcim:device',
accessor=Accessor('termination_a.device'),
@ -650,10 +658,14 @@ class CableTable(BaseTable):
orderable=False,
verbose_name='Component'
)
length = tables.TemplateColumn(
template_code=CABLE_LENGTH,
order_by='_abs_length'
)
class Meta(BaseTable.Meta):
model = Cable
fields = ('pk', 'device_a', 'termination_a', 'device_b', 'termination_b', 'status', 'type', 'color')
fields = ('pk', 'label_', 'device_a', 'termination_a', 'device_b', 'termination_b', 'status', 'type', 'color')
#

View File

@ -48,7 +48,17 @@
<tr>
<td>Color</td>
<td>
<label class="label" style="background-color: #{{ cable.color }}">{{ cable.color }}</label>
<span style="background-color: #{{ cable.color }}">{{ cable.color }}A</span>
</td>
</tr>
<tr>
<td>Length</td>
<td>
{% if cable.length %}
{{ cable.length }} {{ cable.get_length_unit_display }}
{% else %}
<span class="text-muted">N/A</span>
{% endif %}
</td>
</tr>
</table>

View File

@ -7,6 +7,6 @@
</tr>
<tr>
<td>Component</td>
<td>{{ termination_a }}</td>
<td>{{ termination }}</td>
</tr>
</table>

View File

@ -5,6 +5,8 @@ import six
from django.core.serializers import serialize
from django.http import HttpResponse
from dcim.constants import LENGTH_UNIT_CENTIMETER, LENGTH_UNIT_FOOT, LENGTH_UNIT_INCH, LENGTH_UNIT_METER
def csv_format(data):
"""
@ -107,3 +109,21 @@ def serialize_object(obj, extra=None):
data.update(extra)
return data
def to_meters(length, unit):
"""
Convert the given length to meters.
"""
length = int(length)
if length < 0:
raise ValueError("Length must be a positive integer")
if unit == LENGTH_UNIT_METER:
return length
if unit == LENGTH_UNIT_CENTIMETER:
return length / 100
if unit == LENGTH_UNIT_FOOT:
return length * 0.3048
if unit == LENGTH_UNIT_INCH:
return length * 0.3048 * 12
raise ValueError("Unknown unit {}. Must be 'm', 'cm', 'ft', or 'in'.".format(unit))