Horizon Forms¶
Horizon ships with some very useful base form classes, form fields, class-based views, and javascript helpers which streamline most of the common tasks related to form handling.
Form Classes¶
-
class
horizon.forms.base.
DateForm
(*args, **kwargs)[source]¶ A simple form for selecting a range of time.
-
class
horizon.forms.base.
SelfHandlingForm
(request, *args, **kwargs)[source]¶ A base
Form
class which includes processing logic in its subclasses.
Form Fields¶
-
class
horizon.forms.fields.
DynamicChoiceField
(add_item_link=None, add_item_link_args=None, *args, **kwargs)[source]¶ A subclass of
ChoiceField
with additional properties that make dynamically updating its elements easier.Notably, the field declaration takes an extra argument,
add_item_link
which may be a string or callable defining the URL that should be used for the “add” link associated with the field.-
widget
¶ alias of
DynamicSelectWidget
-
-
class
horizon.forms.fields.
DynamicSelectWidget
(attrs=None, choices=(), data_attrs=(), transform=None, transform_html_attrs=None)[source]¶ A subclass of the
Select
widget which renders extra attributes for use in callbacks to handle dynamic changes to the available choices.
-
class
horizon.forms.fields.
DynamicTypedChoiceField
(add_item_link=None, add_item_link_args=None, *args, **kwargs)[source]¶ Simple mix of
DynamicChoiceField
andTypedChoiceField
.
-
class
horizon.forms.fields.
ExternalFileField
(*args, **kwargs)[source]¶ A special flavor of FileField which is meant to be used in cases when instead of uploading file to Django it should be uploaded to some external location, while the form validation is done as usual. Should be paired with ExternalUploadMeta metaclass embedded into the Form class.
-
class
horizon.forms.fields.
ExternalUploadMeta
[source]¶ Set this class as the metaclass of a form that contains ExternalFileField in order to process ExternalFileField fields in a specific way. A hidden CharField twin of FieldField is created which contains just the filename (if any file was selected on browser side) and a special clean method for FileField is defined which extracts just file name. This allows to avoid actual file upload to Django server, yet process form clean() phase as usual. Actual file upload happens entirely on client-side.
-
class
horizon.forms.fields.
IPField
(*args, **kwargs)[source]¶ Form field for entering IP/range values, with validation. Supports IPv4/IPv6 in the format: .. xxx.xxx.xxx.xxx .. xxx.xxx.xxx.xxx/zz .. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff .. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/zz and all compressed forms. Also the short forms are supported: xxx/yy xxx.xxx/yy
-
version
¶ Specifies which IP version to validate, valid values are 1 (fields.IPv4), 2 (fields.IPv6) or both - 3 (fields.IPv4 | fields.IPv6). Defaults to IPv4 (1)
-
mask
¶ Boolean flag to validate subnet masks along with IP address. E.g: 10.0.0.1/32
-
mask_range_from
¶ -
Subnet range limitation, e.g. 16
-
That means the input mask will be checked to be in the range
-
16:max_value. Useful to limit the subnet ranges
-
to A/B/C-class networks.
-
-
class
horizon.forms.fields.
MultiIPField
(*args, **kwargs)[source]¶ Extends IPField to allow comma-separated lists of addresses.
-
class
horizon.forms.fields.
SelectWidget
(attrs=None, choices=(), data_attrs=(), transform=None, transform_html_attrs=None)[source]¶ Customizable select widget, that allows to render data-xxx attributes from choices. This widget also allows user to specify additional html attributes for choices.
-
data_attrs
¶ Specifies object properties to serialize as data-xxx attribute. If passed (‘id’, ), this will be rendered as: <option data-id=”123”>option_value</option> where 123 is the value of choice_value.id
-
transform
¶ A callable used to render the display value from the option object.
-
transform_html_attrs
¶ A callable used to render additional HTML attributes for the option object. It returns a dictionary containing the html attributes and their values. For example, to define a title attribute for the choices:
helpText = { 'Apple': 'This is a fruit', 'Carrot': 'This is a vegetable' } def get_title(data): text = helpText.get(data, None) if text: return {'title': text} else: return {} .... .... widget=forms.ThemableSelect( attrs={'class': 'switchable', 'data-slug': 'source'}, transform_html_attrs=get_title ) self.fields[<field name>].choices = ([ ('apple','Apple'), ('carrot','Carrot') ])
-
-
class
horizon.forms.fields.
ThemableCheckboxInput
(attrs=None, check_test=None)[source]¶ A subclass of the
Checkbox
widget which renders extra markup to allow a custom checkbox experience.
-
class
horizon.forms.fields.
ThemableChoiceField
(choices=(), required=True, widget=None, label=None, initial=None, help_text=u'', *args, **kwargs)[source]¶ Bootstrap based select field.
-
widget
¶ alias of
ThemableSelectWidget
-
Form Views¶
-
class
horizon.forms.views.
ModalBackdropMixin
(*args, **kwargs)[source]¶ This mixin class is to be used for together with ModalFormView and WorkflowView classes to augment them with modal_backdrop context data.
-
class
horizon.forms.views.
ModalFormView
(*args, **kwargs)[source]¶ The main view class from which all views which handle forms in Horizon should inherit. It takes care of all details with processing
SelfHandlingForm
classes, and modal concerns when the associated template inherits from horizon/common/_modal_form.html.Subclasses must define a
form_class
andtemplate_name
attribute at minimum.See Django’s documentation on the FormView class for more details.
Forms Javascript¶
Switchable Fields¶
By marking fields with the "switchable"
and "switched"
classes along
with defining a few data attributes you can programmatically hide, show,
and rename fields in a form.
The triggers are fields using a select
input widget, marked with the
“switchable” class, and defining a “data-slug” attribute. When they are changed,
any input with the "switched"
class and defining a "data-switch-on"
attribute which matches the select
input’s "data-slug"
attribute will be
evaluated for necessary changes. In simpler terms, if the "switched"
target
input’s "switch-on"
matches the "slug"
of the "switchable"
trigger
input, it gets switched. Simple, right?
The "switched"
inputs also need to define states. For each state in which
the input should be shown, it should define a data attribute like the
following: data-<slug>-<value>="<desired label>"
. When the switch event
happens the value of the "switchable"
field will be compared to the
data attributes and the correct label will be applied to the field. If
a corresponding label for that value is not found, the field will
be hidden instead.
A simplified example is as follows:
source = forms.ChoiceField(
label=_('Source'),
choices=[
('cidr', _('CIDR')),
('sg', _('Security Group'))
],
widget=forms.Select(attrs={
'class': 'switchable',
'data-slug': 'source'
})
)
cidr = fields.IPField(
label=_("CIDR"),
required=False,
widget=forms.TextInput(attrs={
'class': 'switched',
'data-switch-on': 'source',
'data-source-cidr': _('CIDR')
})
)
security_group = forms.ChoiceField(
label=_('Security Group'),
required=False,
widget=forms.Select(attrs={
'class': 'switched',
'data-switch-on': 'source',
'data-source-sg': _('Security Group')
})
)
That code would create the "switchable"
control field source
, and the
two "switched"
fields cidr
and security group
which are hidden or
shown depending on the value of source
.
NOTE: A field can only safely define one slug in its "switch-on"
attribute.
While switching on multiple fields is possible, the behavior is very hard to
predict due to the events being fired from the various switchable fields in
order. You generally end up just having it hidden most of the time by accident,
so it’s not recommended. Instead just add a second field to the form and control
the two independently, then merge their results in the form’s clean or handle
methods at the end.