Python – Django Crispy Form Split Field Layouts

djangodjango-crispy-formsdjango-formslayoutpython

We have a crispy form where we want to be able to render different fields in different parts of our forms HTML template, however we can't find a way of doing this in the Crispy Documentation. Below is some slightly made-up code to illustrate what we are trying to do:

forms.py

helper = FormHelper()
helper.layout_1 = Layout(
    Div(
        Field('field_1a'),
        Field('field_1b')
    )
)
helper.layout_2 = Layout(
    Div(
        Field('field_2a'),
        Field('field_2b')
    )
)

template.html

<body>
    {% crispy form layout_1 %}
    <!-- A big bunch of other html -->
    {% crispy form layout_2 %}
</body>

Does anyone know a clean way of achieving this?


The approaches we have looked at so far and had to rule out:

  • We could manually add the fields in our HTML instead of having crispy render them for us. However, this looks to be a no-go because we have a number of choice fields whose options are determined programmatically.
  • We could write a crispy layout which uses an crispy.forms.layout.HTML object to include the HTML which splits up the two different parts of our layout. However, there is a lot of HTML and it would become difficult to maintain if we embedded this directly into python.
  • We could write a Custom Layout Object to do this for us, however we predict this would be quite involved and want to consider this a last resort.
  • We could just not use crispy, and instead look for ways outside of crispy to achieve this, but then we would lose consistency with all the other forms in our application.

Best Answer

Update: This does not work for forms.ModelForm

Try creating two helpers instead of two layouts then explicitly calling your separate helpers. Doing it this way you will have to manually write <form> tags to enclose both forms in your template but hopefully provides the solution you need.

forms.py

class Form(forms.Form):
    field_1a = forms.CharField()
    field_1b = forms.CharField()
    field_2a = forms.CharField()
    field_2b = forms.CharField()

    def __init__(self, *args, **kwargs):
        super(Form, self).__init__(*args, **kwargs)
        self.helper1 = FormHelper()
        self.helper1.form_tag = False
        self.helper1.layout = Layout(
            Div(
                Field('field_1a'),
                Field('field_1b')
            )
        )

        self.helper2 = FormHelper()
        self.helper2.form_tag = False
        self.helper2.disable_csrf = True
        self.helper2.layout = Layout(
            Div(
                Field('field_2a'),
                Field('field_2b')
            )
        )

Then in your template:

<body>
<form>
{% crispy form form.helper1 %}
<!-- A big bunch of other html -->
{% crispy form form.helper2 %}
</form>
</body>
Related Topic