Skip to content

Commit

Permalink
Fixes #5146: Add custom fields support for cables, power panels, rack…
Browse files Browse the repository at this point in the history
… reservations, and virtual chassis
  • Loading branch information
jeremystretch committed Sep 17, 2020
1 parent 91eca8c commit 0030fe1
Show file tree
Hide file tree
Showing 14 changed files with 80 additions and 21 deletions.
4 changes: 4 additions & 0 deletions docs/release-notes/version-2.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

**NOTE:** This release completely removes support for embedded graphs.

### New Features

* [#5146](https://github.com/netbox-community/netbox/issues/5146) - Add custom fields support for cables, power panels, rack reservations, and virtual chassis

### Other Changes

* [#4349](https://github.com/netbox-community/netbox/issues/4349) - Dropped support for embedded graphs
Expand Down
15 changes: 8 additions & 7 deletions netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,15 @@ class RackUnitSerializer(serializers.Serializer):
occupied = serializers.BooleanField(read_only=True)


class RackReservationSerializer(TaggedObjectSerializer, ValidatedModelSerializer):
class RackReservationSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackreservation-detail')
rack = NestedRackSerializer()
user = NestedUserSerializer()
tenant = NestedTenantSerializer(required=False, allow_null=True)

class Meta:
model = RackReservation
fields = ['id', 'url', 'rack', 'units', 'created', 'user', 'tenant', 'description', 'tags']
fields = ['id', 'url', 'rack', 'units', 'created', 'user', 'tenant', 'description', 'tags', 'custom_fields']


class RackElevationDetailFilterSerializer(serializers.Serializer):
Expand Down Expand Up @@ -649,7 +649,7 @@ class Meta:
# Cables
#

class CableSerializer(TaggedObjectSerializer, ValidatedModelSerializer):
class CableSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
termination_a_type = ContentTypeField(
queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS)
Expand All @@ -667,6 +667,7 @@ class Meta:
fields = [
'id', 'url', 'termination_a_type', 'termination_a_id', 'termination_a', 'termination_b_type',
'termination_b_id', 'termination_b', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'tags',
'custom_fields',
]

def _get_termination(self, obj, side):
Expand Down Expand Up @@ -729,21 +730,21 @@ def get_interface_a(self, obj):
# Virtual chassis
#

class VirtualChassisSerializer(TaggedObjectSerializer, ValidatedModelSerializer):
class VirtualChassisSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
master = NestedDeviceSerializer(required=False)
member_count = serializers.IntegerField(read_only=True)

class Meta:
model = VirtualChassis
fields = ['id', 'url', 'name', 'domain', 'master', 'tags', 'member_count']
fields = ['id', 'url', 'name', 'domain', 'master', 'tags', 'custom_fields', 'member_count']


#
# Power panels
#

class PowerPanelSerializer(TaggedObjectSerializer, ValidatedModelSerializer):
class PowerPanelSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerpanel-detail')
site = NestedSiteSerializer()
rack_group = NestedRackGroupSerializer(
Expand All @@ -755,7 +756,7 @@ class PowerPanelSerializer(TaggedObjectSerializer, ValidatedModelSerializer):

class Meta:
model = PowerPanel
fields = ['id', 'url', 'site', 'rack_group', 'name', 'tags', 'powerfeed_count']
fields = ['id', 'url', 'site', 'rack_group', 'name', 'tags', 'custom_fields', 'powerfeed_count']


class PowerFeedSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
Expand Down
10 changes: 5 additions & 5 deletions netbox/dcim/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ class RackElevationFilterForm(RackFilterForm):
# Rack reservations
#

class RackReservationForm(BootstrapMixin, TenancyForm, forms.ModelForm):
class RackReservationForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False
Expand Down Expand Up @@ -3608,7 +3608,7 @@ def clean_termination_b_id(self):
return getattr(self.cleaned_data['termination_b_id'], 'pk', None)


class CableForm(BootstrapMixin, forms.ModelForm):
class CableForm(BootstrapMixin, CustomFieldModelForm):
tags = DynamicModelMultipleChoiceField(
queryset=Tag.objects.all(),
required=False
Expand Down Expand Up @@ -3919,7 +3919,7 @@ class DeviceSelectionForm(forms.Form):
)


class VirtualChassisCreateForm(BootstrapMixin, forms.ModelForm):
class VirtualChassisCreateForm(BootstrapMixin, CustomFieldModelForm):
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False
Expand Down Expand Up @@ -3972,7 +3972,7 @@ def save(self, *args, **kwargs):
return instance


class VirtualChassisForm(BootstrapMixin, forms.ModelForm):
class VirtualChassisForm(BootstrapMixin, CustomFieldModelForm):
master = forms.ModelChoiceField(
queryset=Device.objects.all(),
required=False,
Expand Down Expand Up @@ -4152,7 +4152,7 @@ class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm):
# Power panels
#

class PowerPanelForm(BootstrapMixin, forms.ModelForm):
class PowerPanelForm(BootstrapMixin, CustomFieldModelForm):
site = DynamicModelChoiceField(
queryset=Site.objects.all()
)
Expand Down
23 changes: 23 additions & 0 deletions netbox/dcim/migrations/0116_custom_field_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Migration(migrations.Migration):
]

operations = [
# Original CustomFieldModels
migrations.AddField(
model_name='device',
name='custom_field_data',
Expand All @@ -34,4 +35,26 @@ class Migration(migrations.Migration):
name='custom_field_data',
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
),

# Added under #5146
migrations.AddField(
model_name='cable',
name='custom_field_data',
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
),
migrations.AddField(
model_name='powerpanel',
name='custom_field_data',
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
),
migrations.AddField(
model_name='rackreservation',
name='custom_field_data',
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
),
migrations.AddField(
model_name='virtualchassis',
name='custom_field_data',
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
),
]
8 changes: 4 additions & 4 deletions netbox/dcim/models/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -882,8 +882,8 @@ def get_status_class(self):
# Cables
#

@extras_features('custom_links', 'export_templates', 'webhooks')
class Cable(ChangeLoggedModel):
@extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
class Cable(ChangeLoggedModel, CustomFieldModel):
"""
A physical connection between two endpoints.
"""
Expand Down Expand Up @@ -1168,8 +1168,8 @@ def get_compatible_types(self):
# Virtual chassis
#

@extras_features('custom_links', 'export_templates', 'webhooks')
class VirtualChassis(ChangeLoggedModel):
@extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
class VirtualChassis(ChangeLoggedModel, CustomFieldModel):
"""
A collection of Devices which operate with a shared control plane (e.g. a switch stack).
"""
Expand Down
4 changes: 2 additions & 2 deletions netbox/dcim/models/power.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
# Power
#

@extras_features('custom_links', 'export_templates', 'webhooks')
class PowerPanel(ChangeLoggedModel):
@extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
class PowerPanel(ChangeLoggedModel, CustomFieldModel):
"""
A distribution point for electrical power; e.g. a data center RPP.
"""
Expand Down
4 changes: 2 additions & 2 deletions netbox/dcim/models/racks.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,8 @@ def get_power_utilization(self):
return 0


@extras_features('custom_links', 'export_templates', 'webhooks')
class RackReservation(ChangeLoggedModel):
@extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
class RackReservation(ChangeLoggedModel, CustomFieldModel):
"""
One or more reserved units within a Rack.
"""
Expand Down
1 change: 1 addition & 0 deletions netbox/templates/dcim/cable.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ <h1>{% block title %}Cable {{ cable }}{% endblock %}</h1>
</tr>
</table>
</div>
{% include 'inc/custom_fields_panel.html' with obj=cable %}
{% include 'extras/inc/tags_panel.html' with tags=cable.tags.all url='dcim:cable_list' %}
{% plugin_left_page cable %}
</div>
Expand Down
8 changes: 8 additions & 0 deletions netbox/templates/dcim/inc/cable_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@
{% render_field form.tags %}
</div>
</div>
{% if form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
</div>
</div>
{% endif %}
1 change: 1 addition & 0 deletions netbox/templates/dcim/powerpanel.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ <h1>{% block title %}{{ powerpanel }}{% endblock %}</h1>
</tr>
</table>
</div>
{% include 'inc/custom_fields_panel.html' with obj=powerpanel %}
{% include 'extras/inc/tags_panel.html' with tags=powerpanel.tags.all url='dcim:powerpanel_list' %}
{% plugin_left_page powerpanel %}
</div>
Expand Down
1 change: 1 addition & 0 deletions netbox/templates/dcim/rackreservation.html
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ <h1>{% block title %}{{ rackreservation }}{% endblock %}</h1>
</tr>
</table>
</div>
{% include 'inc/custom_fields_panel.html' with obj=rackreservation %}
{% include 'extras/inc/tags_panel.html' with tags=rackreservation.tags.all url='dcim:rackreservation_list' %}
{% plugin_left_page rackreservation %}
</div>
Expand Down
8 changes: 8 additions & 0 deletions netbox/templates/dcim/rackreservation_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,12 @@
{% render_field form.tenant %}
</div>
</div>
{% if form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
</div>
</div>
{% endif %}
{% endblock %}
1 change: 1 addition & 0 deletions netbox/templates/dcim/virtualchassis.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ <h1>{% block title %}{{ virtualchassis }}{% endblock %}</h1>
</tr>
</table>
</div>
{% include 'inc/custom_fields_panel.html' with obj=virtualchassis %}
{% include 'extras/inc/tags_panel.html' with tags=virtualchassis.tags.all url='dcim:virtualchassis_list' %}
{% plugin_left_page virtualchassis %}
</div>
Expand Down
13 changes: 12 additions & 1 deletion netbox/templates/dcim/virtualchassis_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,20 @@ <h3>{% block title %}{% if vc_form.instance %}Editing {{ vc_form.instance }}{% e
<div class="panel panel-default">
<div class="panel-heading"><strong>Virtual Chassis</strong></div>
<div class="table panel-body">
{% render_form vc_form %}
{% render_field vc_form.name %}
{% render_field vc_form.domain %}
{% render_field vc_form.master %}
{% render_field vc_form.tags %}
</div>
</div>
{% if vc_form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields vc_form %}
</div>
</div>
{% endif %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Members</strong></div>
<table class="table panel-body">
Expand Down

0 comments on commit 0030fe1

Please sign in to comment.