0% found this document useful (0 votes)
314 views

Django Crispy Forms Pygrunn

This document provides an overview of the django-crispy-forms library. It discusses how crispy-forms can be used to customize the rendering of Django forms, including reordering fields, adding CSS classes and attributes, and using layout objects to define custom form structures programmatically. Key features covered include the crispy filter for easy div formatting of forms, the {% crispy %} tag for customization via helpers and layouts, and how to define custom layout objects and override templates.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
314 views

Django Crispy Forms Pygrunn

This document provides an overview of the django-crispy-forms library. It discusses how crispy-forms can be used to customize the rendering of Django forms, including reordering fields, adding CSS classes and attributes, and using layout objects to define custom form structures programmatically. Key features covered include the crispy filter for easy div formatting of forms, the {% crispy %} tag for customization via helpers and layouts, and how to define custom layout objects and override templates.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 70

django-crispy-forms

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>

How about divs?

Reorder fields?

Django forms
class ExampleForm(forms.Form):
email = forms.CharField()
username = forms.CharField()

Moving chunks of code

Django forms
class ExampleForm(forms.Form):

class ExampleForm(forms.Form):

email = forms.CharField()

username = forms.CharField()

username = forms.CharField()

email = forms.CharField()

Moving chunks of code

Django forms
class ExampleForm(forms.Form):
email = forms.CharField()
username = forms.CharField()
class ExtraFieldForm(ExampleForm):
comment = forms.CharField()

Make comment the first field?

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')

ModelForms are different, why?

Customize output?

Asteriks for required fields


{% for field in form %}
{{ field }} {% if field.field.required %}(*){% endif %}
{% endfor %}

Asteriks for required fields


{% for field in form %}
{{ field }} {% if field.field.required %}(*){% endif %}
{% endfor %}

What about field.errors ?


What about form.non_field_errors ?
etc.

Something more
complex?

django-crispy-forms

Formerly known as django-uni-form, created by Daniel Greenfeld


@pydanny in 2008

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

Easy div format


No need to change form code at all
{% load crispy_forms_tags %}
{{ example_form|crispy }}

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

I don't like writing HTML for forms


I need customization power
They need to be as DRY as possible

{% 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 %}

How do we customize this output?

<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>

FormHelper

They control global form rendering behaviour


They are form decoupled

FormHelper attributes

form_method: helper.form_method = 'post'


form_action: helper.form_action = 'addItem'
form_id
form_class
form_tag: helper.form_tag = False

FormHelper
helpers.py

class ExampleFormHelper(FormHelper):
form_method = 'post'
form_id = 'example-form-id'
Template

{% crispy example_form example_form_helper %}

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 %}

Custom FormHelper attributes


forms.py

class ExampleForm(forms.Form):
helper = FormHelper()
helper.help_text_as_placeholder = True
Crispy-forms Templates

{{ help_text_as_placeholder }}

Programmatic
layouts

Special attribute layout and Layout class


forms.py

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

Custom output is defined by a Python layout


Flexible and highly reusable

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(

Beware that layouts are rendered strict

'comment',
'username',
css_id="div-wrapping-comment-and-username"
),
)

Layouts
Layout power comes from layout objects:

They are Python classes


Every layout object has an associated template

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')

Nested Layout objects


Div(
Div(
'name',
'value'
),
HTML("Hero?")
)

Crispy-forms internals

Layout has a fields attribute


All layout objects have a fields attribute

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'
)

Custom Layout object


TR('username')
<tr><td>{{ field }}</td></tr>

Custom Layout object


class TR(object):

template = 'myTemplate.html' # <tr><td>{{ field|safe }}</td></tr>


def __init__(self, field):
self.field = field
def render(self, form, form_style, context):
field = render_field(field, form, form_style, context)
return render_to_string(self.template, Context({'field': field}))

Examples

Crispy-forms
templates

Templates

Can be easily overriden at various levels


There are layout templates and global templates

Overriding Layout objects templates


Globally

from crispy_forms.layout import Div


Div.template = 'mydiv.html'

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 %}

{% crispy_field field %} != {{ field }}

{% include 'bootstrap/layout/help_text_and_errors.html' %}
{% endif %}
</div>

Examples

All selects using chosen


class AnimalForm(forms.form):
animal = forms.ChoiceField(choices=[
('cat', 'cat'),
('dog', 'dog'),
])
food = forms.ChoiceField(choices=[
('meat', 'meat'),
('fish', 'fish'),
])
helper = FormHelper()
helper.form_class = 'form-horizontal'

$(document).ready(function () {
$(".chzn-select").chosen();
});

All selects using chosen


field.html
{% if field|css_class == "select" %}
<div class="controls">
{% crispy_field field 'class' 'chzn-select' %}
</div>
{% endif %}
{% if field|css_class != "checkboxselectmultiple" and
field|css_class != "radioselect" and
field|css_class != "select" %}
[...]

Field labels as holders

.holder {
color: #999;
font-size: 19px;
position: relative;
left: -210px;
top: 4px;
}

Field labels as holders


field.html (Using a custom attribute)
{% if not label_as_holder and field.label and not field|is_checkbox %}
<label for="{{ field.id_for_label }}" class="control-label" ...> {{ field.label|safe }} </label>
{% endif %}
{% crispy_field field %}
{% if label_as_holder %}
<span class="holder {% if field.value %}hidden{% endif %}">{{ field.label }}</span>
{% endif %}

Scratching the surface

There is more power, filters, layout objects, attributes, etc.


Javascript validation
Visit the docs django-crispy-forms.rtfd.org
There is more coming

Thanks,
questions?
@maraujop

You might also like