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
Miguel Araujo
May 16, 2012
Programming
14
7.7k
django-crispy-forms
Pygrunn
2012 Keynote given by Miguel Araujo (
@maraujop
) about
django-crispy-forms
Miguel Araujo
May 16, 2012
Tweet
Share
More Decks by Miguel Araujo
See All by Miguel Araujo
DSLs can't parse that! ♫
maraujop
1
610
Python, the good parts
maraujop
3
2.6k
Red-Light HAL
maraujop
3
410
Taller de Django en español
maraujop
15
3k
Advanced Django Forms Usage
maraujop
20
3.9k
Other Decks in Programming
See All in Programming
AIと人間の共創開発!OSSで試行錯誤した開発スタイル
mae616
2
880
予防に勝る防御なし(2025年版) - 堅牢なコードを導く様々な設計のヒント / Growing Reliable Code PHP Conference Fukuoka 2025
twada
PRO
19
4.7k
퇴근 후 1억이 거래되는 서비스 만들기 | 내가 AI를 사용하는 방법
maryang
2
420
Pythonに漸進的に型をつける
nealle
1
160
alien-signals と自作 OSS で実現する フレームワーク非依存な ロジック共通化の探求 / Exploring Framework-Agnostic Logic Sharing with alien-signals and Custom OSS
aoseyuu
3
5.5k
オンデバイスAIとXcode
ryodeveloper
0
390
スキーマ駆動で、Zod OpenAPI Honoによる、API開発するために、Hono Takibiというライブラリを作っている
nakita628
0
340
ALL CODE BASE ARE BELONG TO STUDY
uzulla
30
6.9k
ドメイン駆動設計のエッセンス
masuda220
PRO
15
7.4k
実践Claude Code:20の失敗から学ぶAIペアプログラミング
takedatakashi
18
9.5k
釣り地図SNSにおける有料機能の実装
nokonoko1203
0
200
Bakuraku E2E Scenario Test System Architecture #bakuraku_qa_study
teyamagu
PRO
0
260
Featured
See All Featured
Keith and Marios Guide to Fast Websites
keithpitt
412
23k
Reflections from 52 weeks, 52 projects
jeffersonlam
355
21k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
23
1.5k
Raft: Consensus for Rubyists
vanstee
140
7.2k
Code Review Best Practice
trishagee
72
19k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Why You Should Never Use an ORM
jnunemaker
PRO
60
9.6k
It's Worth the Effort
3n
187
28k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.7k
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
GraphQLとの向き合い方2022年版
quramy
49
14k
Faster Mobile Websites
deanohume
310
31k
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