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

This commit is contained in:
jeremystretch 2022-01-18 11:09:12 -05:00
parent 1584d51433
commit 38963e7960
5 changed files with 48 additions and 13 deletions

View File

@ -2,6 +2,10 @@
## v3.1.7 (FUTURE) ## 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) ## v3.1.6 (2022-01-17)

View File

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

View File

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

View File

@ -9,7 +9,8 @@ LINKTERMINATION = """
""" """
CABLE_LENGTH = """ 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 = """ CABLE_TERMINATION_PARENT = """

View File

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