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
580
Python, the good parts
maraujop
3
2.5k
Red-Light HAL
maraujop
3
390
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
エンジニア向けCursor勉強会 @ SmartHR
yukisnow1823
0
120
ウォンテッドリーの「ココロオドル」モバイル開発 / Wantedly's "kokoro odoru" mobile development
kubode
1
170
これだけは知っておきたいクラス設計の基礎知識 version 2
masuda220
PRO
24
6.5k
スモールスタートで始めるためのLambda×モノリス(Lambdalith)
akihisaikeda
2
300
RuboCop: Modularity and AST Insights
koic
2
1.6k
MCP調べてみました! / Exploring MCP
uhzz
2
2.3k
Amazon CloudWatchの地味だけど強力な機能紹介!
itotsum
0
180
AIコーディングエージェントを 「使いこなす」ための実践知と現在地 in ログラス / How to Use AI Coding Agent in Loglass
rkaga
4
690
Cursor/Devin全社導入の理想と現実
saitoryc
22
16k
AWS で実現する安全な AI エージェントの作り方 〜 Bedrock Engineer の実装例を添えて 〜 / how-to-build-secure-ai-agents
gawa
8
860
Dissecting and Reconstructing Ruby Syntactic Structures
ydah
1
830
REALITY コマンド作成チュートリアル
nishiuriraku
0
110
Featured
See All Featured
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
5.4k
Making Projects Easy
brettharned
116
6.1k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
Java REST API Framework Comparison - PWX 2021
mraible
30
8.5k
Side Projects
sachag
453
42k
Why You Should Never Use an ORM
jnunemaker
PRO
55
9.3k
Writing Fast Ruby
sferik
628
61k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
60k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.2k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Reflections from 52 weeks, 52 projects
jeffersonlam
349
20k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
160
15k
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