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:
@ -317,3 +317,14 @@ COMPATIBLE_TERMINATION_TYPES = {
|
|||||||
'frontport': ['consoleport', 'consoleserverport', 'interface', 'frontport', 'rearport'],
|
'frontport': ['consoleport', 'consoleserverport', 'interface', 'frontport', 'rearport'],
|
||||||
'rearport': ['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'),
|
||||||
|
)
|
@ -786,10 +786,19 @@ class VirtualChassisFilter(django_filters.FilterSet):
|
|||||||
|
|
||||||
|
|
||||||
class CableFilter(django_filters.FilterSet):
|
class CableFilter(django_filters.FilterSet):
|
||||||
|
q = django_filters.CharFilter(
|
||||||
|
method='search',
|
||||||
|
label='Search',
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cable
|
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):
|
class ConsoleConnectionFilter(django_filters.FilterSet):
|
||||||
|
@ -2211,7 +2211,7 @@ class CableForm(BootstrapMixin, forms.ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cable
|
model = Cable
|
||||||
fields = ('type', 'status', 'label', 'color')
|
fields = ('type', 'status', 'label', 'color', 'length', 'length_unit')
|
||||||
|
|
||||||
|
|
||||||
class CableFilterForm(BootstrapMixin, forms.Form):
|
class CableFilterForm(BootstrapMixin, forms.Form):
|
||||||
|
@ -123,6 +123,9 @@ class Migration(migrations.Migration):
|
|||||||
('status', models.BooleanField(default=True)),
|
('status', models.BooleanField(default=True)),
|
||||||
('label', models.CharField(blank=True, max_length=100)),
|
('label', models.CharField(blank=True, max_length=100)),
|
||||||
('color', utilities.fields.ColorField(blank=True, max_length=6)),
|
('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_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')),
|
('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')),
|
||||||
],
|
],
|
||||||
|
@ -20,7 +20,7 @@ from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange
|
|||||||
from utilities.fields import ColorField, NullableCharField
|
from utilities.fields import ColorField, NullableCharField
|
||||||
from utilities.managers import NaturalOrderByManager
|
from utilities.managers import NaturalOrderByManager
|
||||||
from utilities.models import ChangeLoggedModel
|
from utilities.models import ChangeLoggedModel
|
||||||
from utilities.utils import serialize_object
|
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 CableQuerySet, InterfaceQuerySet
|
from .querysets import CableQuerySet, InterfaceQuerySet
|
||||||
@ -2366,6 +2366,22 @@ class Cable(ChangeLoggedModel):
|
|||||||
color = ColorField(
|
color = ColorField(
|
||||||
blank=True
|
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()
|
objects = CableQuerySet.as_manager()
|
||||||
|
|
||||||
@ -2383,6 +2399,14 @@ class Cable(ChangeLoggedModel):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:cable', args=[self.pk])
|
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):
|
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
|
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
|
return termination
|
||||||
|
|
||||||
# Find the cable (if any) attached to the peer port
|
# 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 no cable exists, return None
|
||||||
if next_cable is None:
|
if next_cable is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Return the far side termination of the cable
|
# 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)
|
return trace_cable(self.termination_a), trace_cable(self.termination_b)
|
||||||
|
@ -170,6 +170,10 @@ VIRTUALCHASSIS_ACTIONS = """
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CABLE_LENGTH = """
|
||||||
|
{% if record.length %}{{ record.length }}{{ record.length_unit }}{% else %}—{% endif %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Regions
|
# Regions
|
||||||
@ -626,6 +630,10 @@ class CableTable(BaseTable):
|
|||||||
args=[Accessor('pk')],
|
args=[Accessor('pk')],
|
||||||
verbose_name='PK'
|
verbose_name='PK'
|
||||||
)
|
)
|
||||||
|
label_ = tables.Column(
|
||||||
|
accessor=Accessor('label'),
|
||||||
|
verbose_name='Label'
|
||||||
|
)
|
||||||
device_a = tables.LinkColumn(
|
device_a = tables.LinkColumn(
|
||||||
viewname='dcim:device',
|
viewname='dcim:device',
|
||||||
accessor=Accessor('termination_a.device'),
|
accessor=Accessor('termination_a.device'),
|
||||||
@ -650,10 +658,14 @@ class CableTable(BaseTable):
|
|||||||
orderable=False,
|
orderable=False,
|
||||||
verbose_name='Component'
|
verbose_name='Component'
|
||||||
)
|
)
|
||||||
|
length = tables.TemplateColumn(
|
||||||
|
template_code=CABLE_LENGTH,
|
||||||
|
order_by='_abs_length'
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = Cable
|
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')
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -48,7 +48,17 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Color</td>
|
<td>Color</td>
|
||||||
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -7,6 +7,6 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Component</td>
|
<td>Component</td>
|
||||||
<td>{{ termination_a }}</td>
|
<td>{{ termination }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -5,6 +5,8 @@ import six
|
|||||||
from django.core.serializers import serialize
|
from django.core.serializers import serialize
|
||||||
from django.http import HttpResponse
|
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):
|
def csv_format(data):
|
||||||
"""
|
"""
|
||||||
@ -107,3 +109,21 @@ def serialize_object(obj, extra=None):
|
|||||||
data.update(extra)
|
data.update(extra)
|
||||||
|
|
||||||
return data
|
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))
|
||||||
|
Reference in New Issue
Block a user