Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
django-crispy-forms
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Miguel Araujo
May 16, 2012
Programming
7.7k
14
Share
django-crispy-forms
Pygrunn
2012 Keynote given by Miguel Araujo (
@maraujop
) about
django-crispy-forms
Miguel Araujo
May 16, 2012
More Decks by Miguel Araujo
See All by Miguel Araujo
DSLs can't parse that! ♫
maraujop
1
630
Python, the good parts
maraujop
3
2.7k
Red-Light HAL
maraujop
3
440
Taller de Django en español
maraujop
15
3k
Advanced Django Forms Usage
maraujop
20
4k
Other Decks in Programming
See All in Programming
書籍「ユーザーストーリーマッピング」が私のバイブル
asumikam
4
370
JOAI2026 1st solution - heron0519 -
heron0519
0
140
〜バイブコーディングを超えて〜 チームで実験し続けたAI駆動開発
tigertora7571
0
110
Radical Imagining - LIFT 2025-2027 Policy Agenda
lift1998
0
370
forteeの改修から振り返るPHPerKaigi 2026
muno92
PRO
3
290
Server-Side Kotlin LT大会 vol.18 [Kotlin-lspの最新情報と Neovimのlsp設定例]
yasunori0418
1
150
YJITとZJITにはイカなる違いがあるのか?
nakiym
0
220
おれのAgentic Coding 2026/03
tsukasagr
1
150
Kubernetes上でAgentを動かすための最新動向と押さえるべき概念まとめ
sotamaki0421
3
510
AI時代のPhpStorm最新事情 #phpcon_odawara
yusuke
0
190
PHP で mp3 プレイヤーを実装しよう
m3m0r7
PRO
0
280
セグメントとターゲットを意識するプロポーザルの書き方 〜採択の鍵は、誰に刺すかを見極めるマーケティング戦略にある〜
m3m0r7
PRO
0
550
Featured
See All Featured
The SEO identity crisis: Don't let AI make you average
varn
0
440
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
180
YesSQL, Process and Tooling at Scale
rocio
174
15k
Optimising Largest Contentful Paint
csswizardry
37
3.6k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
440
Fireside Chat
paigeccino
42
3.9k
The Invisible Side of Design
smashingmag
303
52k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
120
The browser strikes back
jonoalderson
0
980
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
160
Embracing the Ebb and Flow
colly
88
5k
Transcript
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 Moving chunks of code class ExampleForm(forms.Form): email =
forms.CharField() username = forms.CharField() •
class ExampleForm(forms.Form): email = forms.CharField() username = forms.CharField() class ExampleForm(forms.Form):
username = forms.CharField() email = forms.CharField() Django forms Moving chunks of code •
Django forms Make comment the first field? class ExampleForm(forms.Form): email
= forms.CharField() username = forms.CharField() class ExtraFieldForm(ExampleForm): comment = forms.CharField() •
Django forms self.fields is a SortedDict self.fields.keyOrder is a list
['username', 'email', 'comment'] class ExtraFieldForm(ExampleForm): comment = forms.CharField() def __init__(self, *args, **kwargs): super(ExtraFieldForm, self).__init__(*args, **kwargs) self.fields.keyOrder = ['comment', 'email', 'username'] • •
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 ModelForms are different, why? class ExampleForm(forms.ModelForm): class Meta:
model = ExampleModel fields = ('username', 'email') •
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?
None
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> [...]
None
{% 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 %} <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> How do we customize this output?
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 Template class ExampleFormHelper(FormHelper): form_method = 'post' form_id =
'example-form-id' {% crispy example_form example_form_helper %}
forms.py class ExampleForm(forms.Form): helper = ExampleFormHelper() Template {% crispy example_form
%} Attaching FormHelper helpers.py class ExampleFormHelper(FormHelper): layout = Layout('comment', 'username', 'email')
Coupled FormHelper forms.py Template class ExampleForm(forms.Form): helper = FormHelper() helper.form_method
= 'post' helper.form_id = 'example-form-id' {% crispy example_form %}
Custom FormHelper attributes forms.py Crispy-forms Templates class ExampleForm(forms.Form): helper =
FormHelper() helper.help_text_as_placeholder = True {{ help_text_as_placeholder }}
Programmatic layouts
Special attribute layout and Layout class forms.py Template class ExtraFieldForm(forms.Form):
helper = FormHelper() helper.layout = Layout('comment', 'username', 'email') {% crispy example_form %}
Layout( 'comment', 'email', 'username', ) Layouts Basic Layout for ExtraFieldForm
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( 'comment', 'username',
css_id="div-wrapping-comment-and-username" ), ) Beware that layouts are rendered strict
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 In Crispy-forms
class ExampleForm(forms.Form): username = forms.CharField( widget = forms.TextInput(attrs={'class': 'whatever', 'autocomplete': 'off'}) ) Field('username', css_class='whatever', autocomplete='off')
Nested Layout objects Div( Div( 'name', 'value' ), HTML("Hero?") )
None
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'] self.fields.append(args) class LayoutChunk(Layout): def __init__(self): self.fields = [ HTML("Hero?"), Div('name') ] GlobalLayout('comment') 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' )
None
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
None
None
Crispy-forms templates
Templates Can be easily overriden at various levels There are
layout templates and global templates • •
Overriding Layout objects templates Globally Individually from crispy_forms.layout import Div
Div.template = 'mydiv.html' 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> {% crispy_field field %} != {{ field }}
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