mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Refactor form rendering components & add docstrings
This commit is contained in:
@ -7,7 +7,7 @@ from ipam.models import ASN
|
||||
from netbox.forms import NetBoxModelForm
|
||||
from tenancy.forms import TenancyForm
|
||||
from utilities.forms.fields import CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField
|
||||
from utilities.forms.rendering import TabbedFieldGroups
|
||||
from utilities.forms.rendering import TabbedGroups
|
||||
from utilities.forms.widgets import DatePicker, NumberWithOptions
|
||||
|
||||
__all__ = (
|
||||
@ -153,7 +153,7 @@ class CircuitTerminationForm(NetBoxModelForm):
|
||||
'term_side',
|
||||
'description',
|
||||
'tags',
|
||||
TabbedFieldGroups(
|
||||
TabbedGroups(
|
||||
(_('Site'), 'site'),
|
||||
(_('Provider Network'), 'provider_network'),
|
||||
),
|
||||
|
@ -16,7 +16,7 @@ from utilities.forms.fields import (
|
||||
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField,
|
||||
NumericArrayField, SlugField,
|
||||
)
|
||||
from utilities.forms.rendering import InlineFields, TabbedFieldGroups
|
||||
from utilities.forms.rendering import InlineFields, TabbedGroups
|
||||
from utilities.forms.widgets import APISelect, ClearableFileInput, HTMXSelect, NumberWithOptions, SelectWithPK
|
||||
from virtualization.models import Cluster
|
||||
from wireless.models import WirelessLAN, WirelessLANGroup
|
||||
@ -237,8 +237,8 @@ class RackForm(TenancyForm, NetBoxModelForm):
|
||||
'width',
|
||||
'starting_unit',
|
||||
'u_height',
|
||||
InlineFields(_('Outer Dimensions'), 'outer_width', 'outer_depth', 'outer_unit'),
|
||||
InlineFields(_('Weight'), 'weight', 'max_weight', 'weight_unit'),
|
||||
InlineFields('outer_width', 'outer_depth', 'outer_unit', label=_('Outer Dimensions')),
|
||||
InlineFields('weight', 'max_weight', 'weight_unit', label=_('Weight')),
|
||||
'mounting_depth',
|
||||
'desc_units',
|
||||
)),
|
||||
@ -1415,7 +1415,7 @@ class InventoryItemForm(DeviceComponentForm):
|
||||
(_('Inventory Item'), ('device', 'parent', 'name', 'label', 'role', 'description', 'tags')),
|
||||
(_('Hardware'), ('manufacturer', 'part_id', 'serial', 'asset_tag')),
|
||||
(_('Component Assignment'), (
|
||||
TabbedFieldGroups(
|
||||
TabbedGroups(
|
||||
(_('Interface'), 'interface'),
|
||||
(_('Console Port'), 'consoleport'),
|
||||
(_('Console Server Port'), 'consoleserverport'),
|
||||
|
@ -16,7 +16,7 @@ from utilities.forms.fields import (
|
||||
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
|
||||
SlugField,
|
||||
)
|
||||
from utilities.forms.rendering import InlineFields, ObjectAttribute, TabbedFieldGroups
|
||||
from utilities.forms.rendering import InlineFields, ObjectAttribute, TabbedGroups
|
||||
from utilities.forms.widgets import DatePicker
|
||||
from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface
|
||||
|
||||
@ -312,7 +312,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
|
||||
(_('IP Address'), ('address', 'status', 'role', 'vrf', 'dns_name', 'description', 'tags')),
|
||||
(_('Tenancy'), ('tenant_group', 'tenant')),
|
||||
(_('Assignment'), (
|
||||
TabbedFieldGroups(
|
||||
TabbedGroups(
|
||||
(_('Device'), 'interface'),
|
||||
(_('Virtual Machine'), 'vminterface'),
|
||||
(_('FHRP Group'), 'fhrpgroup'),
|
||||
@ -725,12 +725,12 @@ class ServiceForm(NetBoxModelForm):
|
||||
|
||||
fieldsets = (
|
||||
(_('Service'), (
|
||||
TabbedFieldGroups(
|
||||
TabbedGroups(
|
||||
(_('Device'), 'device'),
|
||||
(_('Virtual Machine'), 'virtual_machine'),
|
||||
),
|
||||
'name',
|
||||
InlineFields(_('Port(s)'), 'protocol', 'ports'),
|
||||
InlineFields('protocol', 'ports', label=_('Port(s)')),
|
||||
'ipaddresses',
|
||||
'description',
|
||||
'tags',
|
||||
@ -753,11 +753,11 @@ class ServiceCreateForm(ServiceForm):
|
||||
|
||||
fieldsets = (
|
||||
(_('Service'), (
|
||||
TabbedFieldGroups(
|
||||
TabbedGroups(
|
||||
(_('Device'), 'device'),
|
||||
(_('Virtual Machine'), 'virtual_machine'),
|
||||
),
|
||||
TabbedFieldGroups(
|
||||
TabbedGroups(
|
||||
(_('From Template'), 'service_template'),
|
||||
(_('Custom'), 'name', 'protocol', 'ports'),
|
||||
),
|
||||
|
@ -9,8 +9,8 @@
|
||||
{% endfor %}
|
||||
|
||||
{# Render grouped fields according to Form #}
|
||||
{% for group, items in form.fieldsets %}
|
||||
{% render_fieldset form items heading=group %}
|
||||
{% for fieldset in form.fieldsets %}
|
||||
{% render_fieldset form fieldset %}
|
||||
{% endfor %}
|
||||
|
||||
{% if form.custom_fields %}
|
||||
|
@ -3,28 +3,39 @@ import string
|
||||
from functools import cached_property
|
||||
|
||||
__all__ = (
|
||||
'FieldSet',
|
||||
'InlineFields',
|
||||
'ObjectAttribute',
|
||||
'TabbedFieldGroups',
|
||||
'TabbedGroups',
|
||||
)
|
||||
|
||||
|
||||
class FieldGroup:
|
||||
class FieldSet:
|
||||
"""
|
||||
A generic grouping of fields, with an optional name. Each field will be rendered
|
||||
on its own row under the heading (name).
|
||||
"""
|
||||
def __init__(self, *fields, name=None):
|
||||
self.fields = fields
|
||||
self.name = name
|
||||
|
||||
def __init__(self, label, *field_names):
|
||||
self.field_names = field_names
|
||||
|
||||
class InlineFields:
|
||||
"""
|
||||
A set of fields rendered inline (side-by-side) with a shared label; typically nested within a FieldSet.
|
||||
"""
|
||||
def __init__(self, *fields, label=None):
|
||||
self.fields = fields
|
||||
self.label = label
|
||||
|
||||
|
||||
class InlineFields(FieldGroup):
|
||||
pass
|
||||
|
||||
|
||||
class TabbedFieldGroups:
|
||||
|
||||
class TabbedGroups:
|
||||
"""
|
||||
Two or more groups of fields (FieldSets) arranged under tabs among which the user can navigate.
|
||||
"""
|
||||
def __init__(self, *groups):
|
||||
self.groups = [
|
||||
FieldGroup(*group) for group in groups
|
||||
FieldSet(*group, name=name) for name, *group in groups
|
||||
]
|
||||
|
||||
# Initialize a random ID for the group (for tab selection)
|
||||
@ -37,13 +48,15 @@ class TabbedFieldGroups:
|
||||
return [
|
||||
{
|
||||
'id': f'{self.id}_{i}',
|
||||
'title': group.label,
|
||||
'fields': group.field_names,
|
||||
'title': group.name,
|
||||
'fields': group.fields,
|
||||
} for i, group in enumerate(self.groups, start=1)
|
||||
]
|
||||
|
||||
|
||||
class ObjectAttribute:
|
||||
|
||||
"""
|
||||
Renders the value for a specific attribute on the form's instance.
|
||||
"""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django import template
|
||||
|
||||
from utilities.forms.rendering import InlineFields, ObjectAttribute, TabbedFieldGroups
|
||||
from utilities.forms.rendering import FieldSet, InlineFields, ObjectAttribute, TabbedGroups
|
||||
|
||||
__all__ = (
|
||||
'getfield',
|
||||
@ -48,24 +48,29 @@ def widget_type(field):
|
||||
#
|
||||
|
||||
@register.inclusion_tag('form_helpers/render_fieldset.html')
|
||||
def render_fieldset(form, fieldset, heading=None):
|
||||
def render_fieldset(form, fieldset):
|
||||
"""
|
||||
Render a group set of fields.
|
||||
"""
|
||||
# Handle legacy tuple-based fieldset definitions, e.g. (_('Label'), ('field1, 'field2', 'field3'))
|
||||
if type(fieldset) is not FieldSet:
|
||||
name, fields = fieldset
|
||||
fieldset = FieldSet(*fields, name=name)
|
||||
|
||||
rows = []
|
||||
for item in fieldset:
|
||||
for item in fieldset.fields:
|
||||
|
||||
# Multiple fields side-by-side
|
||||
if type(item) is InlineFields:
|
||||
fields = [
|
||||
form[name] for name in item.field_names if name in form.fields
|
||||
form[name] for name in item.fields if name in form.fields
|
||||
]
|
||||
rows.append(
|
||||
('inline', item.label, fields)
|
||||
)
|
||||
|
||||
# Tabbed groups of fields
|
||||
elif type(item) is TabbedFieldGroups:
|
||||
elif type(item) is TabbedGroups:
|
||||
tabs = [
|
||||
{
|
||||
'id': tab['id'],
|
||||
@ -95,7 +100,7 @@ def render_fieldset(form, fieldset, heading=None):
|
||||
)
|
||||
|
||||
return {
|
||||
'heading': heading,
|
||||
'heading': fieldset.name,
|
||||
'rows': rows,
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ from ipam.models import IPAddress, RouteTarget, VLAN
|
||||
from netbox.forms import NetBoxModelForm
|
||||
from tenancy.forms import TenancyForm
|
||||
from utilities.forms.fields import CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField
|
||||
from utilities.forms.rendering import TabbedFieldGroups
|
||||
from utilities.forms.rendering import TabbedGroups
|
||||
from utilities.forms.utils import add_blank_choice, get_field_value
|
||||
from utilities.forms.widgets import HTMXSelect
|
||||
from virtualization.models import VirtualMachine, VMInterface
|
||||
@ -448,7 +448,7 @@ class L2VPNTerminationForm(NetBoxModelForm):
|
||||
fieldsets = (
|
||||
(None, (
|
||||
'l2vpn',
|
||||
TabbedFieldGroups(
|
||||
TabbedGroups(
|
||||
(_('VLAN'), 'vlan'),
|
||||
(_('Device'), 'interface'),
|
||||
(_('Virtual Machine'), 'vminterface'),
|
||||
|
Reference in New Issue
Block a user