.. `layouts`: ======= Layouts ======= Fundamentals ~~~~~~~~~~~~ Django-crispy-forms defines another powerful class called ``Layout``, which allows you to change the way the form fields are rendered. This allows you to set the order of the fields, wrap them in divs or other structures, add html, set ids, classes or attributes to whatever you want, etc. And all that without writing a custom form template, using programmatic layouts. Just attach the layout to a helper, layouts are optional, but probably the most powerful thing django-crispy-forms has to offer. A ``Layout`` is constructed by layout objects, which can be thought of as form components. All these components are explained later in :ref:`layout objects`, what you need to know now about them is that every component renders a different template and has a different purpose. Let’s write a couple of different layouts for our form, continuing with our form class example (note that the full form is not shown again). Let's add a layout to our helper:: from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout, Fieldset, Submit class ExampleForm(forms.Form): [...] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.layout = Layout( Fieldset( 'first arg is the legend of the fieldset', 'like_website', 'favorite_number', 'favorite_color', 'favorite_food', 'notes' ), Submit('submit', 'Submit', css_class='button white'), ) When we render the form now using:: {% load crispy_forms_tags %} {% crispy example_form %} We will get the fields wrapped in a fieldset, whose legend will be set to 'first arg is the legend of the fieldset'. The fields' order will be: ``like_website``, ``favorite_number``, ``favorite_color``, ``favorite_food`` and ``notes``. We also get a submit button which will be styled with Bootstrap's ``btn btn-primary`` classes. This is just the tip of the iceberg: now imagine you want to add an explanation for what notes are, you can use ``HTML`` layout object:: Layout( Fieldset( 'Tell us your favorite stuff {{ username }}', 'like_website', 'favorite_number', 'favorite_color', 'favorite_food', HTML("""

We use notes to get better, please help us {{ username }}

"""), 'notes' ) ) As you'll notice the fieldset legend is context aware and you can write it as if it were a chunk of a template where the form will be rendered. The ``HTML`` object will add a message before the notes input and it's also context aware. Note how you can wrap layout objects into other layout objects. Layout objects ``Fieldset``, ``Div``, ``MultiField`` and ``ButtonHolder`` can hold other Layout objects within. Let's do an alternative layout for the same form:: Layout( MultiField( 'Tell us your favorite stuff {{ username }}', Div( 'like_website', 'favorite_number', css_id = 'special-fields' ), 'favorite_color', 'favorite_food', 'notes' ) ) This time we are using a ``MultiField``, which is a layout object that as a general rule can be used in the same places as ``Fieldset``. The main difference is that this renders all the fields wrapped in a div and when there are errors in the form submission, they are shown in a list instead of each one surrounding the field. Sometimes the best way to see what layout objects do, is just try them and play with them a little bit. Layout objects attributes ~~~~~~~~~~~~~~~~~~~~~~~~~ All layout objects you can set kwargs that will be used as HTML attributes. For example if you want to turn autocomplete off for a field you can do:: Field('field_name', autocomplete='off') If you want to set html attributes, with words separated by hyphens like ``data-name``, as Python doesn't support hyphens in keyword arguments and hyphens are the usual notation in HTML, underscores will be translated into hyphens, so you would do:: Field('field_name', data_name="whatever") As ``class`` is a reserved keyword in Python, for it you will have to use ``css_class``. For example:: Field('field_name', css_class="black-fields") And id attribute is set using ``css_id``:: Field('field_name', css_id="custom_field_id") .. _`layout objects`: Universal layout objects ~~~~~~~~~~~~~~~~~~~~~~~~ These ones live in module ``crispy_forms.layout``. These are layout objects that are not specific to a template pack. We'll go one by one, showing usage examples: - **Div**: It wraps fields in a ``
``:: Div('form_field_1', 'form_field_2', 'form_field_3', ...) **NOTE** Mainly in all layout objects you can set kwargs that will be used as HTML attributes. As ``class`` is a reserved keyword in Python, for it you will have to use ``css_class``. For example:: Div('form_field_1', style="background: white;", title="Explication title", css_class="bigdivs") - **HTML**: A very powerful layout object. Use it to render pure html code. In fact it behaves as a Django template and it has access to the whole context of the page where the form is being rendered. This layout object doesn't accept any extra parameters than the html to render, you cannot set html attributes like in ``Div``:: HTML("{% if success %}

Operation was successful

{% endif %}") .. warning :: Beware that this is rendered in a standalone template, so if you are using custom templatetags or filters, don't forget to add your ``{% load custom_tags %}`` - **Field**: Extremely useful layout object. You can use it to set attributes in a field or render a specific field with a custom template. This way you avoid having to explicitly override the field's widget and pass an ugly ``attrs`` dictionary:: Field('password', id="password-field", css_class="passwordfields", title="Explanation") Field('slider', template="custom-slider.html") This layout object can be used to easily extend Django's widgets. If you want to render a Django form field as hidden you can simply do:: Field('field_name', type="hidden") If you need HTML5 attributes, you can easily do those using underscores ``data_name`` kwarg here will become into ``data-name`` in your generated html:: Field('field_name', data_name="special") Fields in bootstrap are wrapped in a ``
``. You may want to set extra classes in this div, for that do:: Field('field_name', wrapper_class="extra-class") - **Submit**: Used to create a submit button. First parameter is the ``name`` attribute of the button, second parameter is the ``value`` attribute:: Submit('search', 'SEARCH') Renders to:: - **Hidden**: Used to create a hidden input:: Hidden('name', 'value') - **Button**: Creates a button:: Button('name', 'value') - **Reset**: Used to create a reset input:: reset = Reset('name', 'value') - **Fieldset**: It wraps fields in a ``
``. The first parameter is the text for the fieldset legend, as we've said it behaves like a Django template:: Fieldset("Text for the legend {{ username }}", 'form_field_1', 'form_field_2' ) - **ButtonHolder**: It wraps fields in a ``
``, this is a legacy layout object from the ``uni-form`` template pack:: ButtonHolder( HTML(''), Submit('save', 'Save') ) - **MultiField**: It wraps fields in a ``
`` with a label on top. When there are errors in the form submission it renders them in a list instead of each one surrounding the field:: MultiField("Text for the label {{ username }}", 'form_field_1', 'form_field_2' ) Bootstrap Layout objects ~~~~~~~~~~~~~~~~~~~~~~~~ These ones live under module ``crispy_forms.bootstrap``. - **FormActions**: It wraps fields in a ``
``. It is usually used to wrap form's buttons:: FormActions( Submit('save', 'Save changes'), Button('cancel', 'Cancel') ) .. image:: images/form_actions.png :align: center - **AppendedText**: It renders a bootstrap appended text input. The first parameter is the name of the field to add appended text to. The second is the appended text which can be wrapped in Django's `mark_safe`_ to allow it to be HTML like. There is an optional parameter ``active``, by default set to ``False``, that you can set to a boolean to render appended text active. See `input_size`_ to change the size of this input:: AppendedText('field_name', 'appended text to show') AppendedText('field_name', '$', active=True) .. image:: images/appended_text.png :align: center - **PrependedText**: It renders a bootstrap prepended text input. The first parameter is the name of the field to add prepended text to. The second is the prepended text which can be wrapped in Django's `mark_safe`_ to allow it to be HTML like. There is an optional parameter ``active``, by default set to ``False``, that you can set to a boolean to render prepended text active. See `input_size`_ to change the size of this input:: PrependedText('field_name', mark_safe('Prepended text to show')) PrependedText('field_name', '@', placeholder="username") .. image:: images/prepended_text.png :align: center - **PrependedAppendedText**: It renders a combined prepended and appended text. The first parameter is the name of the field, then the prepended text and finally the appended text. The text can be wrapped in Django's `mark_safe`_ to allow it to be HTML like. See `input_size`_ to change the size of this input:: PrependedAppendedText('field_name', '$', '.00'), .. image:: images/appended_prepended_text.png :align: center - **InlineCheckboxes**: It renders a Django ``forms.MultipleChoiceField`` field using inline checkboxes:: InlineCheckboxes('field_name') .. image:: images/inline_checkboxes.png :align: center - **InlineRadios**: It renders a Django ``forms.ChoiceField`` field with its widget set to ``forms.RadioSelect`` using inline radio buttons:: InlineRadios('field_name') .. image:: images/inline_radios.jpg :align: center - **StrictButton**: It renders a button using ``