Bläddra i källkod

review feedback

Arthur 5 dagar sedan
förälder
incheckning
aab0f18323

+ 1 - 1
netbox/dcim/models/cooling.py

@@ -6,9 +6,9 @@ from django.utils.translation import gettext_lazy as _
 from dcim.choices import *
 from netbox.models import PrimaryModel
 from netbox.models.features import ContactsMixin, ImageAttachmentsMixin
-from netbox.models.mixins import CoolingTemperatureMixin, FlowRateMixin, PressureMixin
 
 from .device_components import CabledObjectModel, PathEndpoint
+from .mixins import CoolingTemperatureMixin, FlowRateMixin, PressureMixin
 
 __all__ = (
     'CoolingFeed',

+ 1 - 2
netbox/dcim/models/device_component_templates.py

@@ -8,11 +8,10 @@ from django.utils.translation import gettext_lazy as _
 from dcim.choices import *
 from dcim.constants import *
 from dcim.models.base import PortMappingBase
-from dcim.models.mixins import InterfaceValidationMixin
+from dcim.models.mixins import DiameterMixin, InterfaceValidationMixin, MaximumFlowMixin
 from dcim.utils import get_module_bay_positions, resolve_module_placeholder
 from netbox.models import ChangeLoggedModel
 from netbox.models.ltree import LtreeManager, LtreeModel
-from netbox.models.mixins import DiameterMixin, MaximumFlowMixin
 from utilities.fields import ColorField, NaturalOrderingField
 from utilities.ordering import naturalize_interface
 from utilities.tracking import TrackingModelMixin

+ 2 - 2
netbox/dcim/models/device_components.py

@@ -12,11 +12,11 @@ from dcim.choices import *
 from dcim.constants import *
 from dcim.fields import WWNField
 from dcim.models.base import PortMappingBase
-from dcim.models.mixins import InterfaceValidationMixin
+from dcim.models.mixins import DiameterMixin, InterfaceValidationMixin, MaximumFlowMixin
 from netbox.choices import ColorChoices
 from netbox.models import NetBoxModel, OrganizationalModel
 from netbox.models.ltree import LtreeManager, LtreeModel, SortPathField
-from netbox.models.mixins import DiameterMixin, MaximumFlowMixin, OwnerMixin
+from netbox.models.mixins import OwnerMixin
 from utilities.fields import ColorField, NaturalOrderingField
 from utilities.ordering import naturalize_interface
 from utilities.query_functions import CollateAsChar

+ 307 - 0
netbox/dcim/models/mixins.py

@@ -1,14 +1,27 @@
 from django.apps import apps
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.core.exceptions import ValidationError
+from django.core.validators import MinValueValidator
 from django.db import models
 from django.utils.translation import gettext_lazy as _
 
 from dcim.constants import VIRTUAL_IFACE_TYPES, WIRELESS_IFACE_TYPES
+from netbox.choices import *
+from utilities.conversion import (
+    to_celsius,
+    to_kilopascals,
+    to_liters_per_minute,
+    to_millimeters,
+)
 
 __all__ = (
     'CachedScopeMixin',
+    'CoolingTemperatureMixin',
+    'DiameterMixin',
+    'FlowRateMixin',
     'InterfaceValidationMixin',
+    'MaximumFlowMixin',
+    'PressureMixin',
     'RenderConfigMixin',
 )
 
@@ -150,3 +163,297 @@ class InterfaceValidationMixin:
         # RF role may be set only for wireless interfaces
         if self.rf_role and self.type not in WIRELESS_IFACE_TYPES:
             raise ValidationError({'rf_role': _("Wireless role may be set only on wireless interfaces.")})
+
+
+class DiameterMixin(models.Model):
+    diameter = models.DecimalField(
+        verbose_name=_('diameter'),
+        max_digits=8,
+        decimal_places=2,
+        blank=True,
+        null=True,
+    )
+    diameter_unit = models.CharField(
+        verbose_name=_('diameter unit'),
+        max_length=50,
+        choices=DiameterUnitChoices,
+        blank=True,
+        null=True,
+    )
+    # Stores the normalized diameter (in millimeters) for database ordering
+    _abs_diameter = models.DecimalField(
+        max_digits=13,
+        decimal_places=4,
+        blank=True,
+        null=True
+    )
+
+    class Meta:
+        abstract = True
+
+    @property
+    def abs_diameter(self):
+        # Public alias for _abs_diameter; Django templates cannot access underscore-prefixed attributes.
+        return self._abs_diameter
+
+    def save(self, *args, **kwargs):
+        # Store the given diameter (if any) in millimeters for use in database ordering
+        if self.diameter is not None and self.diameter_unit:
+            self._abs_diameter = to_millimeters(self.diameter, self.diameter_unit)
+        else:
+            self._abs_diameter = None
+
+        # Clear diameter_unit if no diameter is defined
+        if self.diameter is None:
+            self.diameter_unit = None
+
+        super().save(*args, **kwargs)
+
+    def clean(self):
+        super().clean()
+
+        # Validate diameter and diameter_unit
+        if self.diameter is not None and not self.diameter_unit:
+            raise ValidationError(_("Must specify a unit when setting a diameter"))
+
+
+class FlowRateMixin(models.Model):
+    flow_rate = models.DecimalField(
+        verbose_name=_('flow rate'),
+        max_digits=8,
+        decimal_places=2,
+        blank=True,
+        null=True,
+        validators=[MinValueValidator(0)],
+    )
+    flow_rate_unit = models.CharField(
+        verbose_name=_('flow rate unit'),
+        max_length=50,
+        choices=FlowRateUnitChoices,
+        blank=True,
+        null=True,
+    )
+    # Stores the normalized flow rate (in liters per minute) for database ordering
+    _abs_flow_rate = models.DecimalField(
+        max_digits=13,
+        decimal_places=4,
+        blank=True,
+        null=True
+    )
+
+    class Meta:
+        abstract = True
+
+    @property
+    def abs_flow_rate(self):
+        # Public alias for _abs_flow_rate; Django templates cannot access underscore-prefixed attributes.
+        return self._abs_flow_rate
+
+    def save(self, *args, **kwargs):
+        # Store the given flow rate (if any) in liters per minute for use in database ordering
+        if self.flow_rate is not None and self.flow_rate_unit:
+            self._abs_flow_rate = to_liters_per_minute(self.flow_rate, self.flow_rate_unit)
+        else:
+            self._abs_flow_rate = None
+
+        # Clear flow_rate_unit if no flow rate is defined
+        if self.flow_rate is None:
+            self.flow_rate_unit = None
+
+        super().save(*args, **kwargs)
+
+    def clean(self):
+        super().clean()
+
+        # Validate flow_rate and flow_rate_unit
+        if self.flow_rate is not None and not self.flow_rate_unit:
+            raise ValidationError(_("Must specify a unit when setting a flow rate"))
+
+
+class MaximumFlowMixin(models.Model):
+    maximum_flow = models.DecimalField(
+        verbose_name=_('maximum flow'),
+        max_digits=8,
+        decimal_places=2,
+        blank=True,
+        null=True,
+        validators=[MinValueValidator(0)],
+    )
+    maximum_flow_unit = models.CharField(
+        verbose_name=_('maximum flow unit'),
+        max_length=50,
+        choices=FlowRateUnitChoices,
+        blank=True,
+        null=True,
+    )
+    # Stores the normalized maximum flow (in liters per minute) for database ordering
+    _abs_maximum_flow = models.DecimalField(
+        max_digits=13,
+        decimal_places=4,
+        blank=True,
+        null=True
+    )
+
+    class Meta:
+        abstract = True
+
+    @property
+    def abs_maximum_flow(self):
+        # Public alias for _abs_maximum_flow; Django templates cannot access underscore-prefixed attributes.
+        return self._abs_maximum_flow
+
+    def save(self, *args, **kwargs):
+        # Store the given maximum flow (if any) in liters per minute for use in database ordering
+        if self.maximum_flow is not None and self.maximum_flow_unit:
+            self._abs_maximum_flow = to_liters_per_minute(self.maximum_flow, self.maximum_flow_unit)
+        else:
+            self._abs_maximum_flow = None
+
+        # Clear maximum_flow_unit if no maximum flow is defined
+        if self.maximum_flow is None:
+            self.maximum_flow_unit = None
+
+        super().save(*args, **kwargs)
+
+    def clean(self):
+        super().clean()
+
+        # Validate maximum_flow and maximum_flow_unit
+        if self.maximum_flow is not None and not self.maximum_flow_unit:
+            raise ValidationError(_("Must specify a unit when setting a maximum flow"))
+
+
+class PressureMixin(models.Model):
+    pressure = models.DecimalField(
+        verbose_name=_('pressure'),
+        max_digits=8,
+        decimal_places=2,
+        blank=True,
+        null=True,
+        validators=[MinValueValidator(0)],
+    )
+    pressure_unit = models.CharField(
+        verbose_name=_('pressure unit'),
+        max_length=50,
+        choices=PressureUnitChoices,
+        blank=True,
+        null=True,
+    )
+    # Stores the normalized pressure (in kilopascals) for database ordering
+    _abs_pressure = models.DecimalField(
+        max_digits=13,
+        decimal_places=4,
+        blank=True,
+        null=True
+    )
+
+    class Meta:
+        abstract = True
+
+    @property
+    def abs_pressure(self):
+        # Public alias for _abs_pressure; Django templates cannot access underscore-prefixed attributes.
+        return self._abs_pressure
+
+    def save(self, *args, **kwargs):
+        # Store the given pressure (if any) in kilopascals for use in database ordering
+        if self.pressure is not None and self.pressure_unit:
+            self._abs_pressure = to_kilopascals(self.pressure, self.pressure_unit)
+        else:
+            self._abs_pressure = None
+
+        # Clear pressure_unit if no pressure is defined
+        if self.pressure is None:
+            self.pressure_unit = None
+
+        super().save(*args, **kwargs)
+
+    def clean(self):
+        super().clean()
+
+        # Validate pressure and pressure_unit
+        if self.pressure is not None and not self.pressure_unit:
+            raise ValidationError(_("Must specify a unit when setting a pressure"))
+
+
+class CoolingTemperatureMixin(models.Model):
+    """
+    Adds supply/return temperatures sharing a single unit, with normalized (°C) fields for ordering.
+    """
+    supply_temperature = models.DecimalField(
+        verbose_name=_('supply temperature'),
+        max_digits=6,
+        decimal_places=2,
+        blank=True,
+        null=True,
+        help_text=_('Supply (cold) temperature')
+    )
+    return_temperature = models.DecimalField(
+        verbose_name=_('return temperature'),
+        max_digits=6,
+        decimal_places=2,
+        blank=True,
+        null=True,
+        help_text=_('Return (warm) temperature')
+    )
+    temperature_unit = models.CharField(
+        verbose_name=_('temperature unit'),
+        max_length=50,
+        choices=TemperatureUnitChoices,
+        blank=True,
+        null=True,
+    )
+    # Stores the normalized temperatures (in degrees Celsius) for database ordering
+    _abs_supply_temperature = models.DecimalField(
+        max_digits=8,
+        decimal_places=4,
+        blank=True,
+        null=True
+    )
+    _abs_return_temperature = models.DecimalField(
+        max_digits=8,
+        decimal_places=4,
+        blank=True,
+        null=True
+    )
+
+    class Meta:
+        abstract = True
+
+    @property
+    def abs_supply_temperature(self):
+        # Public alias for _abs_supply_temperature; Django templates cannot access underscore-prefixed attributes.
+        return self._abs_supply_temperature
+
+    @property
+    def abs_return_temperature(self):
+        # Public alias for _abs_return_temperature; Django templates cannot access underscore-prefixed attributes.
+        return self._abs_return_temperature
+
+    def save(self, *args, **kwargs):
+        # Store the given temperatures (if any) in degrees Celsius for use in database ordering
+        if self.temperature_unit:
+            self._abs_supply_temperature = (
+                to_celsius(self.supply_temperature, self.temperature_unit)
+                if self.supply_temperature is not None else None
+            )
+            self._abs_return_temperature = (
+                to_celsius(self.return_temperature, self.temperature_unit)
+                if self.return_temperature is not None else None
+            )
+        else:
+            self._abs_supply_temperature = None
+            self._abs_return_temperature = None
+
+        # Clear temperature_unit if no temperatures are defined
+        if self.supply_temperature is None and self.return_temperature is None:
+            self.temperature_unit = None
+
+        super().save(*args, **kwargs)
+
+    def clean(self):
+        super().clean()
+
+        # A temperature unit is required when a temperature is set
+        if (self.supply_temperature is not None or self.return_temperature is not None) and not self.temperature_unit:
+            raise ValidationError(_("Must specify a unit when setting a temperature"))

+ 1 - 308
netbox/netbox/models/mixins.py

@@ -1,26 +1,13 @@
 from django.core.exceptions import ValidationError
-from django.core.validators import MinValueValidator
 from django.db import models
 from django.utils.translation import gettext_lazy as _
 
 from netbox.choices import *
-from utilities.conversion import (
-    to_celsius,
-    to_grams,
-    to_kilopascals,
-    to_liters_per_minute,
-    to_meters,
-    to_millimeters,
-)
+from utilities.conversion import to_grams, to_meters
 
 __all__ = (
-    'CoolingTemperatureMixin',
-    'DiameterMixin',
     'DistanceMixin',
-    'FlowRateMixin',
-    'MaximumFlowMixin',
     'OwnerMixin',
-    'PressureMixin',
     'WeightMixin',
 )
 
@@ -88,300 +75,6 @@ class WeightMixin(models.Model):
             raise ValidationError(_("Must specify a unit when setting a weight"))
 
 
-class DiameterMixin(models.Model):
-    diameter = models.DecimalField(
-        verbose_name=_('diameter'),
-        max_digits=8,
-        decimal_places=2,
-        blank=True,
-        null=True,
-    )
-    diameter_unit = models.CharField(
-        verbose_name=_('diameter unit'),
-        max_length=50,
-        choices=DiameterUnitChoices,
-        blank=True,
-        null=True,
-    )
-    # Stores the normalized diameter (in millimeters) for database ordering
-    _abs_diameter = models.DecimalField(
-        max_digits=13,
-        decimal_places=4,
-        blank=True,
-        null=True
-    )
-
-    class Meta:
-        abstract = True
-
-    @property
-    def abs_diameter(self):
-        # Public alias for _abs_diameter; Django templates cannot access underscore-prefixed attributes.
-        return self._abs_diameter
-
-    def save(self, *args, **kwargs):
-        # Store the given diameter (if any) in millimeters for use in database ordering
-        if self.diameter is not None and self.diameter_unit:
-            self._abs_diameter = to_millimeters(self.diameter, self.diameter_unit)
-        else:
-            self._abs_diameter = None
-
-        # Clear diameter_unit if no diameter is defined
-        if self.diameter is None:
-            self.diameter_unit = None
-
-        super().save(*args, **kwargs)
-
-    def clean(self):
-        super().clean()
-
-        # Validate diameter and diameter_unit
-        if self.diameter is not None and not self.diameter_unit:
-            raise ValidationError(_("Must specify a unit when setting a diameter"))
-
-
-class FlowRateMixin(models.Model):
-    flow_rate = models.DecimalField(
-        verbose_name=_('flow rate'),
-        max_digits=8,
-        decimal_places=2,
-        blank=True,
-        null=True,
-        validators=[MinValueValidator(0)],
-    )
-    flow_rate_unit = models.CharField(
-        verbose_name=_('flow rate unit'),
-        max_length=50,
-        choices=FlowRateUnitChoices,
-        blank=True,
-        null=True,
-    )
-    # Stores the normalized flow rate (in liters per minute) for database ordering
-    _abs_flow_rate = models.DecimalField(
-        max_digits=13,
-        decimal_places=4,
-        blank=True,
-        null=True
-    )
-
-    class Meta:
-        abstract = True
-
-    @property
-    def abs_flow_rate(self):
-        # Public alias for _abs_flow_rate; Django templates cannot access underscore-prefixed attributes.
-        return self._abs_flow_rate
-
-    def save(self, *args, **kwargs):
-        # Store the given flow rate (if any) in liters per minute for use in database ordering
-        if self.flow_rate is not None and self.flow_rate_unit:
-            self._abs_flow_rate = to_liters_per_minute(self.flow_rate, self.flow_rate_unit)
-        else:
-            self._abs_flow_rate = None
-
-        # Clear flow_rate_unit if no flow rate is defined
-        if self.flow_rate is None:
-            self.flow_rate_unit = None
-
-        super().save(*args, **kwargs)
-
-    def clean(self):
-        super().clean()
-
-        # Validate flow_rate and flow_rate_unit
-        if self.flow_rate is not None and not self.flow_rate_unit:
-            raise ValidationError(_("Must specify a unit when setting a flow rate"))
-
-
-class MaximumFlowMixin(models.Model):
-    maximum_flow = models.DecimalField(
-        verbose_name=_('maximum flow'),
-        max_digits=8,
-        decimal_places=2,
-        blank=True,
-        null=True,
-        validators=[MinValueValidator(0)],
-    )
-    maximum_flow_unit = models.CharField(
-        verbose_name=_('maximum flow unit'),
-        max_length=50,
-        choices=FlowRateUnitChoices,
-        blank=True,
-        null=True,
-    )
-    # Stores the normalized maximum flow (in liters per minute) for database ordering
-    _abs_maximum_flow = models.DecimalField(
-        max_digits=13,
-        decimal_places=4,
-        blank=True,
-        null=True
-    )
-
-    class Meta:
-        abstract = True
-
-    @property
-    def abs_maximum_flow(self):
-        # Public alias for _abs_maximum_flow; Django templates cannot access underscore-prefixed attributes.
-        return self._abs_maximum_flow
-
-    def save(self, *args, **kwargs):
-        # Store the given maximum flow (if any) in liters per minute for use in database ordering
-        if self.maximum_flow is not None and self.maximum_flow_unit:
-            self._abs_maximum_flow = to_liters_per_minute(self.maximum_flow, self.maximum_flow_unit)
-        else:
-            self._abs_maximum_flow = None
-
-        # Clear maximum_flow_unit if no maximum flow is defined
-        if self.maximum_flow is None:
-            self.maximum_flow_unit = None
-
-        super().save(*args, **kwargs)
-
-    def clean(self):
-        super().clean()
-
-        # Validate maximum_flow and maximum_flow_unit
-        if self.maximum_flow is not None and not self.maximum_flow_unit:
-            raise ValidationError(_("Must specify a unit when setting a maximum flow"))
-
-
-class PressureMixin(models.Model):
-    pressure = models.DecimalField(
-        verbose_name=_('pressure'),
-        max_digits=8,
-        decimal_places=2,
-        blank=True,
-        null=True,
-        validators=[MinValueValidator(0)],
-    )
-    pressure_unit = models.CharField(
-        verbose_name=_('pressure unit'),
-        max_length=50,
-        choices=PressureUnitChoices,
-        blank=True,
-        null=True,
-    )
-    # Stores the normalized pressure (in kilopascals) for database ordering
-    _abs_pressure = models.DecimalField(
-        max_digits=13,
-        decimal_places=4,
-        blank=True,
-        null=True
-    )
-
-    class Meta:
-        abstract = True
-
-    @property
-    def abs_pressure(self):
-        # Public alias for _abs_pressure; Django templates cannot access underscore-prefixed attributes.
-        return self._abs_pressure
-
-    def save(self, *args, **kwargs):
-        # Store the given pressure (if any) in kilopascals for use in database ordering
-        if self.pressure is not None and self.pressure_unit:
-            self._abs_pressure = to_kilopascals(self.pressure, self.pressure_unit)
-        else:
-            self._abs_pressure = None
-
-        # Clear pressure_unit if no pressure is defined
-        if self.pressure is None:
-            self.pressure_unit = None
-
-        super().save(*args, **kwargs)
-
-    def clean(self):
-        super().clean()
-
-        # Validate pressure and pressure_unit
-        if self.pressure is not None and not self.pressure_unit:
-            raise ValidationError(_("Must specify a unit when setting a pressure"))
-
-
-class CoolingTemperatureMixin(models.Model):
-    """
-    Adds supply/return temperatures sharing a single unit, with normalized (°C) fields for ordering.
-    """
-    supply_temperature = models.DecimalField(
-        verbose_name=_('supply temperature'),
-        max_digits=6,
-        decimal_places=2,
-        blank=True,
-        null=True,
-        help_text=_('Supply (cold) temperature')
-    )
-    return_temperature = models.DecimalField(
-        verbose_name=_('return temperature'),
-        max_digits=6,
-        decimal_places=2,
-        blank=True,
-        null=True,
-        help_text=_('Return (warm) temperature')
-    )
-    temperature_unit = models.CharField(
-        verbose_name=_('temperature unit'),
-        max_length=50,
-        choices=TemperatureUnitChoices,
-        blank=True,
-        null=True,
-    )
-    # Stores the normalized temperatures (in degrees Celsius) for database ordering
-    _abs_supply_temperature = models.DecimalField(
-        max_digits=8,
-        decimal_places=4,
-        blank=True,
-        null=True
-    )
-    _abs_return_temperature = models.DecimalField(
-        max_digits=8,
-        decimal_places=4,
-        blank=True,
-        null=True
-    )
-
-    class Meta:
-        abstract = True
-
-    @property
-    def abs_supply_temperature(self):
-        # Public alias for _abs_supply_temperature; Django templates cannot access underscore-prefixed attributes.
-        return self._abs_supply_temperature
-
-    @property
-    def abs_return_temperature(self):
-        # Public alias for _abs_return_temperature; Django templates cannot access underscore-prefixed attributes.
-        return self._abs_return_temperature
-
-    def save(self, *args, **kwargs):
-        # Store the given temperatures (if any) in degrees Celsius for use in database ordering
-        if self.temperature_unit:
-            self._abs_supply_temperature = (
-                to_celsius(self.supply_temperature, self.temperature_unit)
-                if self.supply_temperature is not None else None
-            )
-            self._abs_return_temperature = (
-                to_celsius(self.return_temperature, self.temperature_unit)
-                if self.return_temperature is not None else None
-            )
-        else:
-            self._abs_supply_temperature = None
-            self._abs_return_temperature = None
-
-        # Clear temperature_unit if no temperatures are defined
-        if self.supply_temperature is None and self.return_temperature is None:
-            self.temperature_unit = None
-
-        super().save(*args, **kwargs)
-
-    def clean(self):
-        super().clean()
-
-        # A temperature unit is required when a temperature is set
-        if (self.supply_temperature is not None or self.return_temperature is not None) and not self.temperature_unit:
-            raise ValidationError(_("Must specify a unit when setting a temperature"))
-
-
 class DistanceMixin(models.Model):
     distance = models.DecimalField(
         verbose_name=_('distance'),