diff --git a/netbox/circuits/forms/models.py b/netbox/circuits/forms/models.py index bf5d92e85..2246573ba 100644 --- a/netbox/circuits/forms/models.py +++ b/netbox/circuits/forms/models.py @@ -27,15 +27,16 @@ class ProviderForm(NetBoxModelForm): required=False ) + fieldsets = ( + ('Provider', ('name', 'slug', 'asn', 'tags')), + ('Support Info', ('account', 'portal_url', 'noc_contact', 'admin_contact')), + ) + class Meta: model = Provider fields = [ 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags', ] - fieldsets = ( - ('Provider', ('name', 'slug', 'asn', 'tags')), - ('Support Info', ('account', 'portal_url', 'noc_contact', 'admin_contact')), - ) widgets = { 'noc_contact': SmallTextarea( attrs={'rows': 5} @@ -63,14 +64,15 @@ class ProviderNetworkForm(NetBoxModelForm): required=False ) + fieldsets = ( + ('Provider Network', ('provider', 'name', 'service_id', 'description', 'tags')), + ) + class Meta: model = ProviderNetwork fields = [ 'provider', 'name', 'service_id', 'description', 'comments', 'tags', ] - fieldsets = ( - ('Provider Network', ('provider', 'name', 'service_id', 'description', 'tags')), - ) class CircuitTypeForm(NetBoxModelForm): @@ -100,16 +102,17 @@ class CircuitForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('Circuit', ('provider', 'cid', 'type', 'status', 'install_date', 'commit_rate', 'description', 'tags')), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = Circuit fields = [ 'cid', 'type', 'provider', 'status', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant', 'comments', 'tags', ] - fieldsets = ( - ('Circuit', ('provider', 'cid', 'type', 'status', 'install_date', 'commit_rate', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), - ) help_texts = { 'cid': "Unique circuit ID", 'commit_rate': "Committed rate", diff --git a/netbox/dcim/forms/models.py b/netbox/dcim/forms/models.py index 80e785940..92f74036a 100644 --- a/netbox/dcim/forms/models.py +++ b/netbox/dcim/forms/models.py @@ -134,19 +134,20 @@ class SiteForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('Site', ( + 'name', 'slug', 'status', 'region', 'group', 'facility', 'asns', 'time_zone', 'description', 'tags', + )), + ('Tenancy', ('tenant_group', 'tenant')), + ('Contact Info', ('physical_address', 'shipping_address', 'latitude', 'longitude')), + ) + class Meta: model = Site fields = ( 'name', 'slug', 'status', 'region', 'group', 'tenant_group', 'tenant', 'facility', 'asns', 'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'tags', ) - fieldsets = ( - ('Site', ( - 'name', 'slug', 'status', 'region', 'group', 'facility', 'asns', 'time_zone', 'description', 'tags', - )), - ('Tenancy', ('tenant_group', 'tenant')), - ('Contact Info', ('physical_address', 'shipping_address', 'latitude', 'longitude')), - ) widgets = { 'physical_address': SmallTextarea( attrs={ @@ -208,17 +209,18 @@ class LocationForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('Location', ( + 'region', 'site_group', 'site', 'parent', 'name', 'slug', 'description', 'tags', + )), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = Location fields = ( 'region', 'site_group', 'site', 'parent', 'name', 'slug', 'description', 'tenant_group', 'tenant', 'tags', ) - fieldsets = ( - ('Location', ( - 'region', 'site_group', 'site', 'parent', 'name', 'slug', 'description', 'tags', - )), - ('Tenancy', ('tenant_group', 'tenant')), - ) class RackRoleForm(NetBoxModelForm): @@ -347,16 +349,17 @@ class RackReservationForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('Reservation', ('region', 'site', 'location', 'rack', 'units', 'user', 'description', 'tags')), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = RackReservation fields = [ 'region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'tenant_group', 'tenant', 'description', 'tags', ] - fieldsets = ( - ('Reservation', ('region', 'site', 'location', 'rack', 'units', 'user', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), - ) class ManufacturerForm(NetBoxModelForm): @@ -386,21 +389,22 @@ class DeviceTypeForm(NetBoxModelForm): required=False ) + fieldsets = ( + ('Device Type', ( + 'manufacturer', 'model', 'slug', 'part_number', 'tags', + )), + ('Chassis', ( + 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', + )), + ('Images', ('front_image', 'rear_image')), + ) + class Meta: model = DeviceType fields = [ 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'front_image', 'rear_image', 'comments', 'tags', ] - fieldsets = ( - ('Device Type', ( - 'manufacturer', 'model', 'slug', 'part_number', 'tags', - )), - ('Chassis', ( - 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', - )), - ('Images', ('front_image', 'rear_image')), - ) widgets = { 'subdevice_role': StaticSelect(), 'front_image': ClearableFileInput(attrs={ @@ -745,14 +749,15 @@ class PowerPanelForm(NetBoxModelForm): required=False ) + fieldsets = ( + ('Power Panel', ('region', 'site_group', 'site', 'location', 'name', 'tags')), + ) + class Meta: model = PowerPanel fields = [ 'region', 'site_group', 'site', 'location', 'name', 'tags', ] - fieldsets = ( - ('Power Panel', ('region', 'site_group', 'site', 'location', 'name', 'tags')), - ) class PowerFeedForm(NetBoxModelForm): @@ -800,17 +805,18 @@ class PowerFeedForm(NetBoxModelForm): required=False ) + fieldsets = ( + ('Power Panel', ('region', 'site', 'power_panel')), + ('Power Feed', ('rack', 'name', 'status', 'type', 'mark_connected', 'tags')), + ('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')), + ) + class Meta: model = PowerFeed fields = [ 'region', 'site_group', 'site', 'power_panel', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization', 'comments', 'tags', ] - fieldsets = ( - ('Power Panel', ('region', 'site', 'power_panel')), - ('Power Feed', ('rack', 'name', 'status', 'type', 'mark_connected', 'tags')), - ('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')), - ) widgets = { 'status': StaticSelect(), 'type': StaticSelect(), @@ -1101,16 +1107,17 @@ class InventoryItemTemplateForm(BootstrapMixin, forms.ModelForm): widget=forms.HiddenInput ) + fieldsets = ( + ('Inventory Item', ('device_type', 'parent', 'name', 'label', 'role', 'description')), + ('Hardware', ('manufacturer', 'part_id')), + ) + class Meta: model = InventoryItemTemplate fields = [ 'device_type', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'description', 'component_type', 'component_id', ] - fieldsets = ( - ('Inventory Item', ('device_type', 'parent', 'name', 'label', 'role', 'description')), - ('Hardware', ('manufacturer', 'part_id')), - ) widgets = { 'device_type': forms.HiddenInput(), } @@ -1271,6 +1278,17 @@ class InterfaceForm(InterfaceCommonForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('Interface', ('device', 'name', 'type', 'speed', 'duplex', 'label', 'description', 'tags')), + ('Addressing', ('vrf', 'mac_address', 'wwn')), + ('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), + ('Related Interfaces', ('parent', 'bridge', 'lag')), + ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), + ('Wireless', ( + 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'wireless_lan_group', 'wireless_lans', + )), + ) + class Meta: model = Interface fields = [ @@ -1278,17 +1296,6 @@ class InterfaceForm(InterfaceCommonForm, NetBoxModelForm): 'mgmt_only', 'mark_connected', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'wireless_lans', 'untagged_vlan', 'tagged_vlans', 'vrf', 'tags', ] - fieldsets = ( - ('Interface', ('device', 'name', 'type', 'speed', 'duplex', 'label', 'description', 'tags')), - ('Addressing', ('vrf', 'mac_address', 'wwn')), - ('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), - ('Related Interfaces', ('parent', 'bridge', 'lag')), - ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), - ('Wireless', ( - 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'wireless_lan_group', - 'wireless_lans', - )), - ) widgets = { 'device': forms.HiddenInput(), 'type': StaticSelect(), @@ -1432,16 +1439,17 @@ class InventoryItemForm(NetBoxModelForm): required=False ) + fieldsets = ( + ('Inventory Item', ('device', 'parent', 'name', 'label', 'role', 'description', 'tags')), + ('Hardware', ('manufacturer', 'part_id', 'serial', 'asset_tag')), + ) + class Meta: model = InventoryItem fields = [ 'device', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'component_type', 'component_id', 'tags', ] - fieldsets = ( - ('Inventory Item', ('device', 'parent', 'name', 'label', 'role', 'description', 'tags')), - ('Hardware', ('manufacturer', 'part_id', 'serial', 'asset_tag')), - ) widgets = { 'device': forms.HiddenInput(), } diff --git a/netbox/extras/forms/models.py b/netbox/extras/forms/models.py index 5c29a8381..c391665b3 100644 --- a/netbox/extras/forms/models.py +++ b/netbox/extras/forms/models.py @@ -30,16 +30,17 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm): limit_choices_to=FeatureQuery('custom_fields') ) + fieldsets = ( + ('Custom Field', ('name', 'label', 'type', 'object_type', 'weight', 'required', 'description')), + ('Assigned Models', ('content_types',)), + ('Behavior', ('filter_logic',)), + ('Values', ('default', 'choices')), + ('Validation', ('validation_minimum', 'validation_maximum', 'validation_regex')), + ) + class Meta: model = CustomField fields = '__all__' - fieldsets = ( - ('Custom Field', ('name', 'label', 'type', 'object_type', 'weight', 'required', 'description')), - ('Assigned Models', ('content_types',)), - ('Behavior', ('filter_logic',)), - ('Values', ('default', 'choices')), - ('Validation', ('validation_minimum', 'validation_maximum', 'validation_regex')), - ) widgets = { 'type': StaticSelect(), 'filter_logic': StaticSelect(), @@ -52,13 +53,14 @@ class CustomLinkForm(BootstrapMixin, forms.ModelForm): limit_choices_to=FeatureQuery('custom_links') ) + fieldsets = ( + ('Custom Link', ('name', 'content_type', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')), + ('Templates', ('link_text', 'link_url')), + ) + class Meta: model = CustomLink fields = '__all__' - fieldsets = ( - ('Custom Link', ('name', 'content_type', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')), - ('Templates', ('link_text', 'link_url')), - ) widgets = { 'button_class': StaticSelect(), 'link_text': forms.Textarea(attrs={'class': 'font-monospace'}), @@ -77,14 +79,15 @@ class ExportTemplateForm(BootstrapMixin, forms.ModelForm): limit_choices_to=FeatureQuery('export_templates') ) + fieldsets = ( + ('Export Template', ('name', 'content_type', 'description')), + ('Template', ('template_code',)), + ('Rendering', ('mime_type', 'file_extension', 'as_attachment')), + ) + class Meta: model = ExportTemplate fields = '__all__' - fieldsets = ( - ('Export Template', ('name', 'content_type', 'description')), - ('Template', ('template_code',)), - ('Rendering', ('mime_type', 'file_extension', 'as_attachment')), - ) widgets = { 'template_code': forms.Textarea(attrs={'class': 'font-monospace'}), } @@ -96,18 +99,19 @@ class WebhookForm(BootstrapMixin, forms.ModelForm): limit_choices_to=FeatureQuery('webhooks') ) + fieldsets = ( + ('Webhook', ('name', 'content_types', 'enabled')), + ('Events', ('type_create', 'type_update', 'type_delete')), + ('HTTP Request', ( + 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret', + )), + ('Conditions', ('conditions',)), + ('SSL', ('ssl_verification', 'ca_file_path')), + ) + class Meta: model = Webhook fields = '__all__' - fieldsets = ( - ('Webhook', ('name', 'content_types', 'enabled')), - ('Events', ('type_create', 'type_update', 'type_delete')), - ('HTTP Request', ( - 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret', - )), - ('Conditions', ('conditions',)), - ('SSL', ('ssl_verification', 'ca_file_path')), - ) labels = { 'type_create': 'Creations', 'type_update': 'Updates', @@ -123,14 +127,15 @@ class WebhookForm(BootstrapMixin, forms.ModelForm): class TagForm(BootstrapMixin, forms.ModelForm): slug = SlugField() + fieldsets = ( + ('Tag', ('name', 'slug', 'color', 'description')), + ) + class Meta: model = Tag fields = [ 'name', 'slug', 'color', 'description' ] - fieldsets = ( - ('Tag', ('name', 'slug', 'color', 'description')), - ) class ConfigContextForm(BootstrapMixin, forms.ModelForm): diff --git a/netbox/ipam/forms/models.py b/netbox/ipam/forms/models.py index e86fe1dab..68016a0e5 100644 --- a/netbox/ipam/forms/models.py +++ b/netbox/ipam/forms/models.py @@ -53,17 +53,18 @@ class VRFForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('VRF', ('name', 'rd', 'enforce_unique', 'description', 'tags')), + ('Route Targets', ('import_targets', 'export_targets')), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = VRF fields = [ 'name', 'rd', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tenant_group', 'tenant', 'tags', ] - fieldsets = ( - ('VRF', ('name', 'rd', 'enforce_unique', 'description', 'tags')), - ('Route Targets', ('import_targets', 'export_targets')), - ('Tenancy', ('tenant_group', 'tenant')), - ) labels = { 'rd': "RD", } @@ -78,15 +79,16 @@ class RouteTargetForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('Route Target', ('name', 'description', 'tags')), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = RouteTarget fields = [ 'name', 'description', 'tenant_group', 'tenant', 'tags', ] - fieldsets = ( - ('Route Target', ('name', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), - ) class RIRForm(NetBoxModelForm): @@ -113,15 +115,16 @@ class AggregateForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('Aggregate', ('prefix', 'rir', 'date_added', 'description', 'tags')), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = Aggregate fields = [ 'prefix', 'rir', 'date_added', 'description', 'tenant_group', 'tenant', 'tags', ] - fieldsets = ( - ('Aggregate', ('prefix', 'rir', 'date_added', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), - ) help_texts = { 'prefix': "IPv4 or IPv6 network", 'rir': "Regional Internet Registry responsible for this prefix", @@ -146,15 +149,16 @@ class ASNForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('ASN', ('asn', 'rir', 'sites', 'description', 'tags')), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = ASN fields = [ 'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'tags' ] - fieldsets = ( - ('ASN', ('asn', 'rir', 'sites', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), - ) help_texts = { 'asn': "AS number", 'rir': "Regional Internet Registry responsible for this prefix", @@ -248,17 +252,18 @@ class PrefixForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('Prefix', ('prefix', 'status', 'vrf', 'role', 'is_pool', 'mark_utilized', 'description', 'tags')), + ('Site/VLAN Assignment', ('region', 'site_group', 'site', 'vlan_group', 'vlan')), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = Prefix fields = [ 'prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'description', 'tenant_group', 'tenant', 'tags', ] - fieldsets = ( - ('Prefix', ('prefix', 'status', 'vrf', 'role', 'is_pool', 'mark_utilized', 'description', 'tags')), - ('Site/VLAN Assignment', ('region', 'site_group', 'site', 'vlan_group', 'vlan')), - ('Tenancy', ('tenant_group', 'tenant')), - ) widgets = { 'status': StaticSelect(), } @@ -279,15 +284,16 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): required=False ) + fieldsets = ( + ('IP Range', ('vrf', 'start_address', 'end_address', 'role', 'status', 'description', 'tags')), + ('Tenancy', ('tenant_group', 'tenant')), + ) + class Meta: model = IPRange fields = [ 'vrf', 'start_address', 'end_address', 'status', 'role', 'description', 'tenant_group', 'tenant', 'tags', ] - fieldsets = ( - ('IP Range', ('vrf', 'start_address', 'end_address', 'role', 'status', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), - ) widgets = { 'status': StaticSelect(), } @@ -562,16 +568,17 @@ class FHRPGroupForm(NetBoxModelForm): label='Status' ) + fieldsets = ( + ('FHRP Group', ('protocol', 'group_id', 'description', 'tags')), + ('Authentication', ('auth_type', 'auth_key')), + ('Virtual IP Address', ('ip_vrf', 'ip_address', 'ip_status')) + ) + class Meta: model = FHRPGroup fields = ( 'protocol', 'group_id', 'auth_type', 'auth_key', 'description', 'ip_vrf', 'ip_address', 'ip_status', 'tags', ) - fieldsets = ( - ('FHRP Group', ('protocol', 'group_id', 'description', 'tags')), - ('Authentication', ('auth_type', 'auth_key')), - ('Virtual IP Address', ('ip_vrf', 'ip_address', 'ip_status')) - ) def save(self, *args, **kwargs): instance = super().save(*args, **kwargs) @@ -699,17 +706,18 @@ class VLANGroupForm(NetBoxModelForm): required=False ) + fieldsets = ( + ('VLAN Group', ('name', 'slug', 'description', 'tags')), + ('Child VLANs', ('min_vid', 'max_vid')), + ('Scope', ('scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster')), + ) + class Meta: model = VLANGroup fields = [ 'name', 'slug', 'description', 'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster', 'min_vid', 'max_vid', 'tags', ] - fieldsets = ( - ('VLAN Group', ('name', 'slug', 'description', 'tags')), - ('Child VLANs', ('min_vid', 'max_vid')), - ('Scope', ('scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster')), - ) widgets = { 'scope_type': StaticSelect, } diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py index 63582a2d9..3fa85f1f7 100644 --- a/netbox/netbox/forms/base.py +++ b/netbox/netbox/forms/base.py @@ -19,7 +19,13 @@ __all__ = ( class NetBoxModelForm(BootstrapMixin, CustomFieldsMixin, forms.ModelForm): """ Base form for creating & editing NetBox models. Adds support for custom fields. + + Attributes: + fieldsets: An iterable of two-tuples which define a heading and field set to display per section of + the rendered form (optional). If not defined, the all fields will be rendered as a single section. """ + fieldsets = () + def _get_content_type(self): return ContentType.objects.get_for_model(self._meta.model) diff --git a/netbox/templates/generic/object_edit.html b/netbox/templates/generic/object_edit.html index 5dc8f995d..fbf7fd394 100644 --- a/netbox/templates/generic/object_edit.html +++ b/netbox/templates/generic/object_edit.html @@ -33,7 +33,7 @@ {% csrf_token %} {% block form %} - {% if form.Meta.fieldsets %} + {% if form.fieldsets %} {# Render hidden fields #} {% for field in form.hidden_fields %} @@ -41,7 +41,7 @@ {% endfor %} {# Render grouped fields according to Form #} - {% for group, fields in form.Meta.fieldsets %} + {% for group, fields in form.fieldsets %}