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.5k
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
560
Python, the good parts
maraujop
3
2.5k
Red-Light HAL
maraujop
3
380
Taller de Django en español
maraujop
15
2.9k
Advanced Django Forms Usage
maraujop
20
3.9k
Other Decks in Programming
See All in Programming
さいきょうのレイヤードアーキテクチャについて考えてみた
yahiru
3
730
Grafana Cloudとソラカメ
devoc
0
140
技術を根付かせる / How to make technology take root
kubode
1
240
『品質』という言葉が嫌いな理由
korimu
0
160
AIの力でお手軽Chrome拡張機能作り
taiseiue
0
170
バックエンドのためのアプリ内課金入門 (サブスク編)
qnighy
8
1.7k
CI改善もDatadogとともに
taumu
0
110
Pythonでもちょっとリッチな見た目のアプリを設計してみる
ueponx
1
480
SRE、開発、QAが協業して挑んだリリースプロセス改革@SRE Kaigi 2025
nealle
3
4.1k
2,500万ユーザーを支えるSREチームの6年間のスクラムのカイゼン
honmarkhunt
6
5.1k
[JAWS-UG横浜 #80] うわっ…今年のServerless アップデート、少なすぎ…?
maroon1st
1
170
個人アプリを2年ぶりにアプデしたから褒めて / I just updated my personal app, praise me!
lovee
0
340
Featured
See All Featured
How GitHub (no longer) Works
holman
313
140k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.3k
Into the Great Unknown - MozCon
thekraken
35
1.6k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
27
1.5k
VelocityConf: Rendering Performance Case Studies
addyosmani
328
24k
How to Think Like a Performance Engineer
csswizardry
22
1.3k
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
Being A Developer After 40
akosma
89
590k
RailsConf 2023
tenderlove
29
1k
Unsuck your backbone
ammeep
669
57k
It's Worth the Effort
3n
184
28k
Side Projects
sachag
452
42k
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