Source code for crispy_forms_foundation.forms
from copy import deepcopy
from django import forms
from django.forms.fields import FileField, ImageField
from django.utils.translation import gettext_lazy as _
from django.urls import reverse, NoReverseMatch
from crispy_forms.helper import FormHelper
from .layout import Submit, HTML, InlineSwitchField
[docs]class FoundationFormMixin(object):
"""
Mixin to implement a layout helper that will automatically build a form
layout.
Generally, you will prefer to use ``FoundationForm`` or
``FoundationModelForm`` instead.
If you still want to directly use this mixin you'll just have to execute
``FoundationFormMixin.init_helper()`` in your form init.
**Attributes**
title
If set, defines the form's title
layout
If set, override the default layout for the form
error_title
Defines the error title for non field errors
form_id
Defines the id of the form
classes
Defines the classes used on the form
action
Defines the action of the form. ``reverse`` will be called on the
value. On failure the value will be assigned as is
method
Defines the method used for the action
attrs
Defines the attributes of the form
switches
If True, will replace all fields checkboxes with switches
submit
Adds a submit button on the form. Can be set to a Submit object or
a string which will be used as the value of the submit button
title_templatestring
Template string used to display form title (if any)
"""
title = None
layout = None
error_title = _("Errors :")
form_id = None
classes = "foundation-form"
action = ""
method = "post"
attrs = {}
switches = True
submit = True
title_templatestring = u"<h3 class=\"subheader\">{0}</h3>"
def init_helper(self):
# Put required HTML attribute on required fields so they are managed by
# Abide (if enabled)
if "data_abide" in self.attrs:
for field_name, field in self.fields.items():
if hasattr(self, 'instance'):
field_value = getattr(self.instance, field_name, None)
else:
field_value = None
if field.required \
and not ((isinstance(field, FileField) or
isinstance(field, ImageField))
and field_value):
field.widget.attrs["required"] = ""
field.abide_msg = _("This field is required.")
if not self.layout:
# Start with an empty layout
self.helper = FormHelper(self)
else:
# Start from the given layout
self.helper = FormHelper()
self.helper.layout = deepcopy(self.layout)
# Try to reverse form_action url, else fallback to use it as a simple
# string
try:
self.helper.form_action = reverse(self.action)
except NoReverseMatch:
self.helper.form_action = self.action
if self.title:
html = HTML(self.title_templatestring.format(self.title))
self.helper.layout.insert(0, html)
if self.form_id is not None:
self.helper.form_id = self.form_id
self.helper.form_class = self.classes
self.helper.form_method = self.method
self.helper.form_error_title = self.error_title
self.helper.attrs = self.attrs
if self.switches:
# Get a list of all fields with their location within the layout
layout_field_names = self.helper.layout.get_field_names()
# Transform checkbox fields to switches element
for pointer in layout_field_names:
if isinstance(self.fields[pointer[1]].widget,
forms.CheckboxInput):
field = InlineSwitchField(pointer[1],
switch_class="inline")
self.replace_layout_object(pointer[0], field)
if self.submit:
if isinstance(self.submit, Submit):
self.helper.add_input(self.submit)
elif isinstance(self.submit, str):
self.helper.add_input(Submit('submit', self.submit))
else:
self.helper.add_input(Submit('submit', _("Submit")))
def replace_layout_object(self, position, instead):
previous_layout_object = None
layout_object = self.helper.layout.fields[position[0]]
for i in position[1:]:
previous_layout_object = layout_object
layout_object = layout_object.fields[i]
if previous_layout_object:
previous_layout_object[-1] = instead
else:
self.helper.layout.fields[position[0]] = instead
[docs]class FoundationForm(FoundationFormMixin, forms.Form):
"""
A **Django form** that inherit from ``FoundationFormMixin`` to
automatically build a form layout
Example:
.. code-block:: python
from django import forms
from crispy_forms_foundation.forms import FoundationForm
class YourForm(FoundationForm):
title = "Testing"
action = 'test'
layout = Layout(Fieldset("Section", "my_field", "my_field_2"))
switches = False
attrs = {'data_abide': ""}
title = forms.CharField(label='Title', required=True)
slug = forms.CharField(label='Slug', required=False)
"""
def __init__(self, *args, **kwargs):
super(FoundationForm, self).__init__(*args, **kwargs)
self.init_helper()
[docs]class FoundationModelForm(FoundationFormMixin, forms.ModelForm):
"""
A **Django Model form** that inherit from ``FoundationFormMixin`` to
automatically build a form layout
Example:
.. code-block:: python
from crispy_forms_foundation.forms import FoundationModelForm
class YourForm(FoundationModelForm):
title = "Testing"
action = 'test'
layout = Layout(Fieldset("Section", "my_field", "my_field_2"))
switches = False
attrs = {'data_abide': ""}
class Meta:
model = MyModel
fields = ['my_field', 'my_field_2', 'my_field_3']
"""
def __init__(self, *args, **kwargs):
super(FoundationModelForm, self).__init__(*args, **kwargs)
self.init_helper()