diff --git a/netbox/dcim/api/serializers_/devicetypes.py b/netbox/dcim/api/serializers_/devicetypes.py index e04668e82..23c27e664 100644 --- a/netbox/dcim/api/serializers_/devicetypes.py +++ b/netbox/dcim/api/serializers_/devicetypes.py @@ -64,7 +64,7 @@ class DeviceTypeSerializer(NetBoxModelSerializer): class ModuleTypeSerializer(NetBoxModelSerializer): manufacturer = ManufacturerSerializer(nested=True) weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True) - airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False, allow_null=True) + airflow = ChoiceField(choices=ModuleAirflowChoices, allow_blank=True, required=False, allow_null=True) class Meta: model = ModuleType diff --git a/netbox/dcim/api/serializers_/racks.py b/netbox/dcim/api/serializers_/racks.py index e05ae6f80..6b9fdd684 100644 --- a/netbox/dcim/api/serializers_/racks.py +++ b/netbox/dcim/api/serializers_/racks.py @@ -65,7 +65,7 @@ class RackTypeSerializer(RackBaseSerializer): nested=True ) airflow = ChoiceField( - choices=DeviceAirflowChoices, + choices=RackAirflowChoices, allow_blank=True, required=False ) @@ -101,7 +101,7 @@ class RackSerializer(RackBaseSerializer): required=False ) airflow = ChoiceField( - choices=DeviceAirflowChoices, + choices=RackAirflowChoices, allow_blank=True, required=False ) diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index 464c396ff..3575aeeec 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -127,6 +127,17 @@ class RackElevationDetailRenderChoices(ChoiceSet): ) +class RackAirflowChoices(ChoiceSet): + + AIRFLOW_FRONT_TO_REAR = 'front-to-rear' + AIRFLOW_REAR_TO_FRONT = 'rear-to-front' + + CHOICES = ( + (AIRFLOW_FRONT_TO_REAR, _('Front to rear')), + (AIRFLOW_REAR_TO_FRONT, _('Rear to front')), + ) + + # # DeviceTypes # @@ -224,6 +235,25 @@ class ModuleStatusChoices(ChoiceSet): ] +class ModuleAirflowChoices(ChoiceSet): + + AIRFLOW_FRONT_TO_REAR = 'front-to-rear' + AIRFLOW_REAR_TO_FRONT = 'rear-to-front' + AIRFLOW_LEFT_TO_RIGHT = 'left-to-right' + AIRFLOW_RIGHT_TO_LEFT = 'right-to-left' + AIRFLOW_SIDE_TO_REAR = 'side-to-rear' + AIRFLOW_PASSIVE = 'passive' + + CHOICES = ( + (AIRFLOW_FRONT_TO_REAR, _('Front to rear')), + (AIRFLOW_REAR_TO_FRONT, _('Rear to front')), + (AIRFLOW_LEFT_TO_RIGHT, _('Left to right')), + (AIRFLOW_RIGHT_TO_LEFT, _('Right to left')), + (AIRFLOW_SIDE_TO_REAR, _('Side to rear')), + (AIRFLOW_PASSIVE, _('Passive')), + ) + + # # ConsolePorts # diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index 5af5a3878..05ab80f2d 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -270,7 +270,7 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm): ) airflow = forms.ChoiceField( label=_('Airflow'), - choices=add_blank_choice(DeviceAirflowChoices), + choices=add_blank_choice(RackAirflowChoices), required=False ) weight = forms.DecimalField( @@ -416,7 +416,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): ) airflow = forms.ChoiceField( label=_('Airflow'), - choices=add_blank_choice(DeviceAirflowChoices), + choices=add_blank_choice(RackAirflowChoices), required=False ) weight = forms.DecimalField( @@ -575,7 +575,7 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm): ) airflow = forms.ChoiceField( label=_('Airflow'), - choices=add_blank_choice(DeviceAirflowChoices), + choices=add_blank_choice(ModuleAirflowChoices), required=False ) weight = forms.DecimalField( diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index d86caf55c..785b4fb42 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -208,7 +208,7 @@ class RackTypeImportForm(NetBoxModelImportForm): ) airflow = CSVChoiceField( label=_('Airflow'), - choices=DeviceAirflowChoices, + choices=RackAirflowChoices, required=False, help_text=_('Airflow direction') ) @@ -281,7 +281,7 @@ class RackImportForm(NetBoxModelImportForm): ) airflow = CSVChoiceField( label=_('Airflow'), - choices=DeviceAirflowChoices, + choices=RackAirflowChoices, required=False, help_text=_('Airflow direction') ) @@ -414,7 +414,7 @@ class ModuleTypeImportForm(NetBoxModelImportForm): ) airflow = CSVChoiceField( label=_('Airflow'), - choices=DeviceAirflowChoices, + choices=ModuleAirflowChoices, required=False, help_text=_('Airflow direction') ) diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index 61dd27d32..c8124aa11 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -269,7 +269,7 @@ class RackBaseFilterForm(NetBoxModelFilterSetForm): ) airflow = forms.MultipleChoiceField( label=_('Airflow'), - choices=add_blank_choice(DeviceAirflowChoices), + choices=add_blank_choice(RackAirflowChoices), required=False ) weight = forms.DecimalField( @@ -645,7 +645,7 @@ class ModuleTypeFilterForm(NetBoxModelFilterSetForm): tag = TagFilterField(model) airflow = forms.MultipleChoiceField( label=_('Airflow'), - choices=add_blank_choice(DeviceAirflowChoices), + choices=add_blank_choice(ModuleAirflowChoices), required=False ) weight = forms.DecimalField( diff --git a/netbox/dcim/migrations/0189_moduletype_airflow_rack_airflow_racktype_airflow.py b/netbox/dcim/migrations/0189_moduletype_airflow_rack_airflow_racktype_airflow.py index 853daea9c..370df90e8 100644 --- a/netbox/dcim/migrations/0189_moduletype_airflow_rack_airflow_racktype_airflow.py +++ b/netbox/dcim/migrations/0189_moduletype_airflow_rack_airflow_racktype_airflow.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.7 on 2024-07-24 09:06 +# Generated by Django 5.0.7 on 2024-07-25 07:00 from django.db import migrations, models diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 1d8fbb163..954a49f6c 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -25,7 +25,7 @@ from netbox.models.features import ContactsMixin, ImageAttachmentsMixin from utilities.fields import ColorField, CounterCacheField, NaturalOrderingField from utilities.tracking import TrackingModelMixin from .device_components import * -from .mixins import AirflowMixin, RenderConfigMixin, WeightMixin +from .mixins import RenderConfigMixin, WeightMixin __all__ = ( @@ -58,7 +58,7 @@ class Manufacturer(ContactsMixin, OrganizationalModel): return reverse('dcim:manufacturer', args=[self.pk]) -class DeviceType(ImageAttachmentsMixin, PrimaryModel, WeightMixin, AirflowMixin): +class DeviceType(ImageAttachmentsMixin, PrimaryModel, WeightMixin): """ A DeviceType represents a particular make (Manufacturer) and model of device. It specifies rack height and depth, as well as high-level functional role(s). @@ -124,6 +124,12 @@ class DeviceType(ImageAttachmentsMixin, PrimaryModel, WeightMixin, AirflowMixin) help_text=_('Parent devices house child devices in device bays. Leave blank ' 'if this device type is neither a parent nor a child.') ) + airflow = models.CharField( + verbose_name=_('airflow'), + max_length=50, + choices=DeviceAirflowChoices, + blank=True + ) front_image = models.ImageField( upload_to='devicetype-images', blank=True @@ -360,7 +366,7 @@ class DeviceType(ImageAttachmentsMixin, PrimaryModel, WeightMixin, AirflowMixin) return self.subdevice_role == SubdeviceRoleChoices.ROLE_CHILD -class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin, AirflowMixin): +class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin): """ A ModuleType represents a hardware element that can be installed within a device and which houses additional components; for example, a line card within a chassis-based switch such as the Cisco Catalyst 6500. Like a @@ -382,6 +388,12 @@ class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin, AirflowMixin) blank=True, help_text=_('Discrete part number (optional)') ) + airflow = models.CharField( + verbose_name=_('airflow'), + max_length=50, + choices=ModuleAirflowChoices, + blank=True + ) clone_fields = ('manufacturer', 'weight', 'weight_unit',) prerequisite_models = ( @@ -535,7 +547,6 @@ class Device( RenderConfigMixin, ConfigContextModel, TrackingModelMixin, - AirflowMixin, PrimaryModel ): """ @@ -640,6 +651,12 @@ class Device( choices=DeviceStatusChoices, default=DeviceStatusChoices.STATUS_ACTIVE ) + airflow = models.CharField( + verbose_name=_('airflow'), + max_length=50, + choices=DeviceAirflowChoices, + blank=True + ) primary_ip4 = models.OneToOneField( to='ipam.IPAddress', on_delete=models.SET_NULL, diff --git a/netbox/dcim/models/mixins.py b/netbox/dcim/models/mixins.py index fc30b05c7..d4a05699c 100644 --- a/netbox/dcim/models/mixins.py +++ b/netbox/dcim/models/mixins.py @@ -73,15 +73,3 @@ class RenderConfigMixin(models.Model): return self.role.config_template if self.platform and self.platform.config_template: return self.platform.config_template - - -class AirflowMixin(models.Model): - airflow = models.CharField( - verbose_name=_('airflow'), - max_length=50, - choices=DeviceAirflowChoices, - blank=True - ) - - class Meta: - abstract = True diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index f0f1dbea2..21012b631 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -22,7 +22,7 @@ from utilities.data import array_to_string, drange from utilities.fields import ColorField, NaturalOrderingField from .device_components import PowerPort from .devices import Device, Module -from .mixins import AirflowMixin, WeightMixin +from .mixins import WeightMixin from .power import PowerFeed __all__ = ( @@ -37,7 +37,7 @@ __all__ = ( # Rack Types # -class RackBase(WeightMixin, PrimaryModel, AirflowMixin): +class RackBase(WeightMixin, PrimaryModel): """ Base class for RackType & Rack. Holds """ @@ -116,6 +116,14 @@ class RackBase(WeightMixin, PrimaryModel, AirflowMixin): null=True ) + # Airflow + airflow = models.CharField( + verbose_name=_('airflow'), + max_length=50, + choices=RackAirflowChoices, + blank=True + ) + class Meta: abstract = True