Procházet zdrojové kódy

Added length and length_unit fields to Cable

Jeremy Stretch před 7 roky
rodič
revize
6bea8cc546

+ 11 - 0
netbox/dcim/constants.py

@@ -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'),
+)

+ 10 - 1
netbox/dcim/filters.py

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

+ 1 - 1
netbox/dcim/forms.py

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

+ 3 - 0
netbox/dcim/migrations/0066_cables.py

@@ -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')),
             ],

+ 27 - 3
netbox/dcim/models.py

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

+ 13 - 1
netbox/dcim/tables.py

@@ -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')
 
 
 #

+ 11 - 1
netbox/templates/dcim/cable.html

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

+ 1 - 1
netbox/templates/dcim/inc/cable_termination.html

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

+ 20 - 0
netbox/utilities/utils.py

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