Просмотр исходного кода

Added length and length_unit fields to Cable

Jeremy Stretch 7 лет назад
Родитель
Сommit
6bea8cc546

+ 11 - 0
netbox/dcim/constants.py

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

+ 10 - 1
netbox/dcim/filters.py

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

+ 1 - 1
netbox/dcim/forms.py

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

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

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

+ 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.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)

+ 13 - 1
netbox/dcim/tables.py

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

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

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

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

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

+ 20 - 0
netbox/utilities/utils.py

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