Răsfoiți Sursa

Fixes #8377: Fix calculation of absolute cable lengths when specified in fractional units

jeremystretch 4 ani în urmă
părinte
comite
38963e7960

+ 4 - 0
docs/release-notes/version-3.1.md

@@ -2,6 +2,10 @@
 
 ## v3.1.7 (FUTURE)
 
+### Bug Fixes
+
+* [#8377](https://github.com/netbox-community/netbox/issues/8377) - Fix calculation of absolute cable lengths when specified in fractional units
+
 ---
 
 ## v3.1.6 (2022-01-17)

+ 31 - 0
netbox/dcim/migrations/0144_fix_cable_abs_length.py

@@ -0,0 +1,31 @@
+from django.db import migrations
+
+from utilities.utils import to_meters
+
+
+def recalculate_abs_length(apps, schema_editor):
+    """
+    Recalculate absolute lengths for all cables with a length and length unit defined. Fixes
+    incorrectly calculated values as reported under bug #8377.
+    """
+    Cable = apps.get_model('dcim', 'Cable')
+
+    cables = Cable.objects.filter(length__isnull=False).exclude(length_unit='')
+    for cable in cables:
+        cable._abs_length = to_meters(cable.length, cable.length_unit)
+
+    Cable.objects.bulk_update(cables, ['_abs_length'], batch_size=100)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dcim', '0143_remove_primary_for_related_name'),
+    ]
+
+    operations = [
+        migrations.RunPython(
+            code=recalculate_abs_length,
+            reverse_code=migrations.RunPython.noop
+        ),
+    ]

+ 1 - 1
netbox/dcim/tables/cables.py

@@ -45,7 +45,7 @@ class CableTable(BaseTable):
     tenant = TenantColumn()
     length = TemplateColumn(
         template_code=CABLE_LENGTH,
-        order_by='_abs_length'
+        order_by=('_abs_length', 'length_unit')
     )
     color = ColorColumn()
     tags = TagColumn(

+ 2 - 1
netbox/dcim/tables/template_code.py

@@ -9,7 +9,8 @@ LINKTERMINATION = """
 """
 
 CABLE_LENGTH = """
-{% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% endif %}
+{% load helpers %}
+{% if record.length %}{{ record.length|simplify_decimal }} {{ record.length_unit }}{% endif %}
 """
 
 CABLE_TERMINATION_PARENT = """

+ 10 - 11
netbox/utilities/utils.py

@@ -1,9 +1,8 @@
 import datetime
 import json
-import urllib
 from collections import OrderedDict
+from decimal import Decimal
 from itertools import count, groupby
-from typing import Any, Dict, List, Tuple
 
 from django.core.serializers import serialize
 from django.db.models import Count, OuterRef, Subquery
@@ -195,15 +194,15 @@ 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")
+    try:
+        if length < 0:
+            raise ValueError("Length must be a positive number")
+    except TypeError:
+        raise TypeError(f"Invalid value '{length}' for length (must be a number)")
 
     valid_units = CableLengthUnitChoices.values()
     if unit not in valid_units:
-        raise ValueError(
-            "Unknown unit {}. Must be one of the following: {}".format(unit, ', '.join(valid_units))
-        )
+        raise ValueError(f"Unknown unit {unit}. Must be one of the following: {', '.join(valid_units)}")
 
     if unit == CableLengthUnitChoices.UNIT_KILOMETER:
         return length * 1000
@@ -212,11 +211,11 @@ def to_meters(length, unit):
     if unit == CableLengthUnitChoices.UNIT_CENTIMETER:
         return length / 100
     if unit == CableLengthUnitChoices.UNIT_MILE:
-        return length * 1609.344
+        return length * Decimal(1609.344)
     if unit == CableLengthUnitChoices.UNIT_FOOT:
-        return length * 0.3048
+        return length * Decimal(0.3048)
     if unit == CableLengthUnitChoices.UNIT_INCH:
-        return length * 0.3048 * 12
+        return length * Decimal(0.3048) * 12
     raise ValueError(f"Unknown unit {unit}. Must be 'km', 'm', 'cm', 'mi', 'ft', or 'in'.")