diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index ce17e7e92..95500d933 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -11,7 +11,7 @@ from extras.models import ConfigTemplate from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VRF from netbox.forms import NetBoxModelForm from tenancy.forms import TenancyForm -from utilities.forms import add_blank_choice +from utilities.forms import add_blank_choice, get_field_value from utilities.forms.fields import ( CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, NumericArrayField, SlugField, ) @@ -252,22 +252,23 @@ class RackForm(TenancyForm, NetBoxModelForm): rack_type = DynamicModelChoiceField( label=_('Rack Type'), queryset=RackType.objects.all(), - required=False + required=False, + help_text=_("Select a pre-defined rack type, or set physical characteristics below.") ) comments = CommentField() fieldsets = ( - FieldSet('site', 'location', 'name', 'status', 'role', 'description', 'tags', name=_('Rack')), + FieldSet('site', 'location', 'name', 'status', 'role', 'rack_type', 'description', 'tags', name=_('Rack')), FieldSet('facility_id', 'serial', 'asset_tag', name=_('Inventory Control')), FieldSet('tenant_group', 'tenant', name=_('Tenancy')), - FieldSet( - 'rack_type', 'form_factor', 'width', 'starting_unit', 'u_height', - InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), - InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), - 'mounting_depth', 'desc_units', name=_('Dimensions') - ), ) + # Fields which cannot be set locally if a RackType is assigned + RACKTYPE_FIELDS = [ + 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', + 'mounting_depth', 'weight', 'weight_unit', 'max_weight' + ] + class Meta: model = Rack fields = [ @@ -280,9 +281,27 @@ class RackForm(TenancyForm, NetBoxModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if self.instance.pk and self.instance.rack_type: - for field_name in self.instance.rack_type.RACK_FIELDS: - self.fields[field_name].disabled = True + # Mimic HTMXSelect() + self.fields['rack_type'].widget.attrs.update({ + 'hx-get': '.', + 'hx-include': '#form_fields', + 'hx-target': '#form_fields', + }) + + # Omit RackType-defined fields if rack_type is set + if get_field_value(self, 'rack_type'): + for field_name in self.RACKTYPE_FIELDS: + del self.fields[field_name] + else: + self.fieldsets = ( + *self.fieldsets, + FieldSet( + 'form_factor', 'width', 'starting_unit', 'u_height', + InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')), + InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')), + 'mounting_depth', 'desc_units', name=_('Dimensions') + ), + ) class RackReservationForm(TenancyForm, NetBoxModelForm): diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 6fe84fe04..933c6b87d 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -126,12 +126,6 @@ class RackType(RackBase): Devices are housed within Racks. Each rack has a defined height measured in rack units, and a front and rear face. Each Rack is assigned to a Site and (optionally) a Location. """ - RACK_FIELDS = [ - 'type', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', - 'outer_depth', 'outer_unit', 'weight', 'weight_unit', 'max_weight', - 'mounting_depth' - ] - manufacturer = models.ForeignKey( to='dcim.Manufacturer', on_delete=models.PROTECT, @@ -401,13 +395,6 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase): 'location': _("Location must be from the same site, {site}.").format(site=self.site) }) - if self.rack_type: - for field_name in self.rack_type.RACK_FIELDS: - if getattr(self, field_name, None) != getattr(self.rack_type, field_name, None): - raise ValidationError({ - field_name: _("Cannot modify field {field_name} if rack_type set.").format(field_name=field_name) - }) - def save(self, *args, **kwargs): if (not self.pk) and self.rack_type: self.form_factor = self.rack_type.form_factor diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html index f5e487c71..2ae9726f7 100644 --- a/netbox/templates/dcim/rack.html +++ b/netbox/templates/dcim/rack.html @@ -43,6 +43,10 @@ {% trans "Status" %} {% badge object.get_status_display bg_color=object.get_status_color %} + + {% trans "Rack Type" %} + {{ object.rack_type|linkify|placeholder }} + {% trans "Role" %} {{ object.role|linkify|placeholder }}