===================================================
BTC Flex Forms
===================================================
Some form mixins, styles and scripts for fast form development.
Detailed documentation is in the "docs" directory.
Quick start
-----------
1. Add "flex_forms" to your INSTALLED_APPS setting like this::
INSTALLED_APPS = (
...
'flex_forms',
)
2. Add static files css::
<link type="text/css" rel="stylesheet" href="{% static 'flex_forms/css/default.css' %}">
3. Classes for usage: `StaticFieldset` designed for rendering only static fieldsets::
# Usage: when you need to display arbitrary static information on the page.
# For example:
# In view:
static_data = StaticFieldset(model_1=some_model, model_2=another_model)
# In form:
grid = {
['field_1', 'field_2'], # etc.
...
}
field_1 = StaticFlexField(label='Data 1', help_text='Field 1')
field_2 = StaticFlexField(data='Some data', label='Data 2')
def __init__(*args, **kwargs)
self.model_1 = kwargs.pop('model_1', None)
self.model_2 = kwargs.pop('model_2', None)
super().__init__(*args, **kwargs)
self.static_fieldset['field_1'].data = self.model_1.field_1 + self.model_2.field_1
...
4. `StaticModelFieldset`::
# Usage: when you need to display static information on a page based on model data.
# For example:
# In view:
my_model = get_object_or_404(MyModel, pk=self.kwargs.get('pk'))
static_model_data = StaticModelFieldset(instance=my_model)
# In form:
# Support is for StaticFlexField only.
grid = {
'_1': ['model_field_1', 'model_field_2'],
'_2': ['separate_static_field'], # etc.
...
}
separate_field = StaticFlexField('This is a static field') # only static fields can be defined.
5. `MixedFlexForm`::
# Usage: when you need to display multiple forms on a page with a mixed arrangement of fields.
# For example:
# In view:
mix = MixedFlexForm([form_1, form_2, formset_1]) # form_1, form_2, formset_1 - must be are flex too!
# In form: static field from the form_2
grid = { /
'_1': ['form_1_field_2', 'form_2_static_field_1', [formset_1_field_1, form_1_field_1]],
'_2': ['separate_field', 'form_1_field_3', 'separate_static_field'], # etc.
... \
} field defined below (non-forms field)
# You can define separate non-forms fields and specify them in grid.
separate_field = forms.CharField()
separate_static_field = StaticFlexField('This is a static field')
# If you use prefixes for forms (this will be needed if the forms have the same field names (formset)),
# you must specify fields with prefixes:
grid = {
['form_1_prefix-form_1_field_2', 'form_2_prefix-form_2_field_1'], # etc.
...
}
6. `FlexForm`, `FlexModelForm` designed for rendering good known django forms - `Form`, `ModelForm` with flex layout::
class CustomFlexForm(FlexForm):
grid = {
'Fields': ['field_1', 'field_2'],
'New row': ['field_3'],
'Controls': ['button'],
...
}
field_1 = forms.MultipleChoiceField(
label='Fruits?',
choices=(('0', 'Apple'), ('1', 'Mango')),
widget=forms.CheckboxSelectMultiple(attrs={
'field_group_class': 'checkbox-as-button checkbox-as-row',
})
)
# static fields support
field_2 = StaticFlexField(
data='Example', label='Example', help_text='Example')
)
field_3 = StaticFlexField(data='Example', label='Example')
button = FlexButton('Submit')
...
7. `FlexFormset`, `FlexModelFormset`, `FlexInlineFormset` - respectively implementation of
`BaseFormSet`, `BaseModelFormSet`, `BaseInlineFormSet`::
formset = formset_factory(CustomFlexForm, FlexFormset, extra=4)
8. Grid: to locate fields you must specify them in `grid` variable as shown below. The dict key is a row title
that allows you to horizontally split field rows. If the title is not needed, it must starts with `_` symbol::
grid = {
'User Info': ['field_1', 'field_2'],
'_1': ['field_3', ['field_4', 'field_5'], 'field_6'],
'_2': ['field_7', 'field_8'],
'_3': ['field_9', 'field_10', 'field_14'],
'_4': ['field_11'],
'_5': ['field_12'],
'_6': ['button'],
}
9. Template tags::
{% load flex_forms %}
{% as_flex form_object %} # use this tag for rendering form or formset
{% flex_form_grid form %} # use this tag for rendering form body generated with form_grid (visible fields)
{% complex_flex_field field %} # use this tag for rendering a single flex field of the form
* Manual template building::
# Create template for the form (or fieldset).
# For example, custom template:
# custom_form_template.html:
{% load flex_forms %}
<form {{ html_params|safe }}>
{% csrf_token %}
{% for field in form.hidden_fields %}
{{ field }}
{% endfor %}
<div class="flex-fields-column">
<div class="flex-fields-row_title">Title</div>
<div class="flex-fields-row">
<div class="flex-fields-block block-with-padding">
{% complex_flex_field form.field_1 %}
{% complex_flex_field form.static_fieldset.field_44 default_value='No value' %}
{% complex_flex_field form.static_fieldset.button %}
</div>
</div>
</div>
<div class="flex-fields-column">
<div class="flex-fields-row_title">Controls</div>
<div class="flex-fields-row">
<div class="flex-fields-block block-with-padding">
{% complex_flex_field form.static_fieldset.button %}
</div>
</div>
</div>
</form>
# In form class set template path:
class MyForm(FlexForm):
template = 'custom_form_template.html'
# In this case form grid does not need to be set up.
10. The appearance of forms should be configured through css-properties, use
:nth-of-type() and :nth-child(n+x):nth-child(-n+x+y) selectors to style rows. Default forms style involved through
built-in style 'flex-form'.
Example
.. image:: https://user-images.githubusercontent.com/33987296/73204264-b7cb5780-414f-11ea-859a-356aecdfd5c7.png