Django Crispy Forms Pygrunn
Django Crispy Forms Pygrunn
Miguel Araujo
@maraujop
Django forms
Django forms
form.as_ul
form.as_p
form.as_table
Django forms
class ExampleForm(forms.Form):
username = forms.CharField()
email = forms.CharField()
Django forms
{{ example_form.as_ul }}
<li>
<label for="id_username">Username:</label>
<input type="text" name="username" id="id_username">
</li>
<li>
<label for="id_email">Email:</label>
<input type="text" name="email" id="id_email">
</li>
Reorder fields?
Django forms
class ExampleForm(forms.Form):
email = forms.CharField()
username = forms.CharField()
Django forms
class ExampleForm(forms.Form):
class ExampleForm(forms.Form):
email = forms.CharField()
username = forms.CharField()
username = forms.CharField()
email = forms.CharField()
Django forms
class ExampleForm(forms.Form):
email = forms.CharField()
username = forms.CharField()
class ExtraFieldForm(ExampleForm):
comment = forms.CharField()
Django forms
class ExtraFieldForm(ExampleForm):
comment = forms.CharField()
def __init__(self, *args, **kwargs):
super(ExtraFieldForm, self).__init__(*args, **kwargs)
self.fields.keyOrder = ['comment', 'email', 'username']
self.fields is a SortedDict
self.fields.keyOrder is a list ['username', 'email', 'comment']
Django forms
What if I have 100 fields?
class ExtraFieldForm(ExampleForm):
comment = forms.CharField()
def __init__(self, *args, **kwargs):
super(ExtraFieldForm, self).__init__(*args, **kwargs)
self.fields.keyOrder.remove('comment')
self.fields.keyOrder.insert(0, 'comment')
Django ModelForms
class ExampleForm(forms.ModelForm):
class Meta:
model = ExampleModel
fields = ('username', 'email')
Customize output?
Something more
complex?
django-crispy-forms
I joined the project in the middle of 2010 and became lead developer
38 contributors
Tested and thoroughly used
Two template packs: bootstrap & uni_form CRISPY_TEMPLATE_PACK
django-crispy-forms
A filter |crispy
A tag {% crispy %}
They work on forms, modelforms and formsets
|crispy filter
Django forms
{{ example_form|crispy }}
<div id="div_id_username" class="clearfix control-group">
<label for="id_username" class="control-label requiredField">Username<span class="asteriskField">*</span></label>
<div class="controls">
<input id="id_username" type="text" class="textinput textInput" name="username">
</div>
</div>
<div id="div_id_email" class="clearfix control-group">
<label for="id_email" class="control-label requiredField">Email<span class="asteriskField">*</span></label>
[...]
{% crispy %} tag
{% crispy %} tag
{% crispy form [helper] %}
{% crispy example_form %}
<form class="" method="post">
<div style="display:none"><input type="hidden" name="csrfmiddlewaretoken" ...></div>
<div id="div_id_username" class="clearfix control-group">
<label for="id_username" class="control-label requiredField">Username<span class="asteriskField">*</span>
</label>
<div class="controls">
<input id="id_username" type="text" class="textinput textInput" name="username">
</div>
</div>
[...]
</form>
{% crispy %} tag
{% crispy form [helper] %}
{% crispy example_form %}
FormHelper
FormHelper attributes
FormHelper
helpers.py
class ExampleFormHelper(FormHelper):
form_method = 'post'
form_id = 'example-form-id'
Template
Attaching FormHelper
helpers.py
class ExampleFormHelper(FormHelper):
layout = Layout('comment', 'username', 'email')
forms.py
class ExampleForm(forms.Form):
helper = ExampleFormHelper()
Template
{% crispy example_form %}
Coupled FormHelper
forms.py
class ExampleForm(forms.Form):
helper = FormHelper()
helper.form_method = 'post'
helper.form_id = 'example-form-id'
Template
{% crispy example_form %}
class ExampleForm(forms.Form):
helper = FormHelper()
helper.help_text_as_placeholder = True
Crispy-forms Templates
{{ help_text_as_placeholder }}
Programmatic
layouts
class ExtraFieldForm(forms.Form):
helper = FormHelper()
helper.layout = Layout('comment', 'username', 'email')
Template
{% crispy example_form %}
Layouts
Basic Layout for ExtraFieldForm
Layout(
'comment',
'email',
'username',
)
Layouts
Layouts
A bit more complex Layout
Layout(
Div(
'comment',
'username',
css_id="div-wrapping-comment-and-username"
),
)
Layouts
A bit more complex Layout
Layout(
Div(
'comment',
'username',
css_id="div-wrapping-comment-and-username"
),
)
Layouts
Layout power comes from layout objects:
Layout objects
Div(
'comment',
'username',
css_id="div-wrapping-fields",
css_class="crispy-divs",
data-markup="crispy rocks"
)
Layout objects
Fieldset(
"This is the legend of the fieldset",
'comment',
'username',
css_class="fieldsets",
)
Layout objects
HTML(
"""<p>HTML code embedded. You can access the context from
where form is rendered. Hi {{ user.username }}</p>"""
)
HTML(
"{% include 'template.html' %}"
)
Layout objects
Submit('name', 'value')
FormActions(
Submit('save_changes', 'Save changes', css_class="btn-primary"),
Submit('cancel', 'Cancel'),
)
Layout objects
Setting attributes to fields
In Django
class ExampleForm(forms.Form):
username = forms.CharField(
widget = forms.TextInput(attrs={'class': 'whatever', 'autocomplete': 'off'})
)
Layout objects
Setting attributes to fields
In Django
class ExampleForm(forms.Form):
username = forms.CharField(
widget = forms.TextInput(attrs={'class': 'whatever', 'autocomplete': 'off'})
)
In Crispy-forms
Field('username', css_class='whatever', autocomplete='off')
Crispy-forms internals
Layout decoupled
class GlobalLayout(Layout):
def __init__(self, *args, **kwargs):
self.fields = ['username', 'email']
GlobalLayout('comment')
self.fields.append(args)
class LayoutChunk(Layout):
def __init__(self):
self.fields = [
HTML("Hero?"),
Div('name')
]
LayoutChunk()
Layout composition
class ComplexForm(forms.ModelForm):
helper = FormHelper()
helper.layout = Layout(
GlobalLayout(),
'extra_field'
)
Dynamic Layouts
views.py
def view(request):
form = ExampleForm()
form.helper.layout.fields.append(HTML("<p>Added extra HTML</p>"))
[...]
return render(request, 'template.html', {'form': form})
Dynamic Layouts
! If you manipulate a helper, use an instance variable
class ExampleForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.layout = Layout(
'comment',
'username'
)
Examples
Crispy-forms
templates
Templates
Individually
Div('field_name', template='mydiv.html')
field.html template
crispy_forms/templates/{bootstrap|uni_form}/field.html
<div id="div_{{ field.auto_id }}" class="...>
<label ...>
{% if field|css_class == 'radioselect' %}
{% include 'bootstrap/layout/radioselect.html' %}
{% endif %}
[...]
{% if field|css_class != "radioselect" and ... %}
{% crispy_field field %}
{% include 'bootstrap/layout/help_text_and_errors.html' %}
{% endif %}
</div>
field.html template
crispy_forms/templates/{bootstrap|uni_form}/field.html
<div id="div_{{ field.auto_id }}" class="...>
<label ...>
{% if field|css_class == 'radioselect' %}
{% include 'bootstrap/layout/radioselect.html' %}
{% endif %}
[...]
{% if field|css_class != "radioselect" and ... %}
{% crispy_field field %}
{% include 'bootstrap/layout/help_text_and_errors.html' %}
{% endif %}
</div>
Examples
$(document).ready(function () {
$(".chzn-select").chosen();
});
.holder {
color: #999;
font-size: 19px;
position: relative;
left: -210px;
top: 4px;
}
Thanks,
questions?
@maraujop