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
퇴근 후 1억이 거래되는 서비스 만들기 | 내가 AI를 사용하는 방법
maryang
2
350
はじめてのDSPy - 言語モデルを『プロンプト』ではなく『プログラミング』するための仕組み
masahiro_nishimi
4
18k
Vueのバリデーション、結局どれを選べばいい? ― 自作バリデーションの限界と、脱却までの道のり ― / Which Vue Validation Library Should We Really Use? The Limits of Self-Made Validation and How I Finally Moved On
neginasu
3
1.8k
マイベストのシンプルなデータ基盤の話 - Googleスイートとのつき合い方 / mybest-simple-data-architecture-google-nized
snhryt
0
120
ネストしたdata classの面倒な更新にさようなら!Lensを作って理解するArrowのOpticsの世界
shiita0903
1
240
フロントエンド開発のためのブラウザ組み込みAI入門
masashi
7
3.7k
なんでRustの環境構築してないのにRust製のツールが動くの? / Why Do Rust-Based Tools Run Without a Rust Environment?
ssssota
14
47k
CSC509 Lecture 10
javiergs
PRO
0
160
ボトムアップの生成AI活用を推進する社内AIエージェント開発
aku11i
0
1.4k
テーブル定義書の構造化抽出して、生成AIでDWH分析を試してみた / devio2025tokyo
kasacchiful
0
370
SwiftDataを使って10万件のデータを読み書きする
akidon0000
0
250
AI 駆動開発におけるコミュニティと AWS CDK の価値
konokenj
5
320
Featured
See All Featured
GraphQLの誤解/rethinking-graphql
sonatard
73
11k
Raft: Consensus for Rubyists
vanstee
140
7.2k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
Building an army of robots
kneath
306
46k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.7k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
37
2.6k
Fireside Chat
paigeccino
41
3.7k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.5k
Code Reviewing Like a Champion
maltzj
526
40k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
Reflections from 52 weeks, 52 projects
jeffersonlam
355
21k
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