4

I’m trying to create a form layout with a few fields that are of a different size than the other fields. What is the best way to do this using crispy-forms? For example, I’m laying out the form in rows where most of the rows have two fields but occasionally a single field will occupy the whole row.

--------------------------------------------------
| First Name            | Last Name              |
--------------------------------------------------
| User Name             | Email                  |
--------------------------------------------------
| Bio                                            |
--------------------------------------------------

In the example layout above, each field is composed of a label and the text input in the actual HTML (I just didn't know how to show this in the question). I’m using Bootstrap 3 so on the first two lines I want the labels to have a class of ’col-sm-2’ and the input fields to have a class of ‘col-sm-4’ so that when rendered, they show up with two fields per row (i.e. 12 columns). However, for the third row with the “Bio” field, I want the input field to be “col-sm-10’ to take up the whole row.

Here is some sample code that is close enough that someone may be able to help.

self.helper = FormHelper(self)
self.helper.form_tag = False
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-sm-2'
self.helper.field_class = 'col-sm-4'
self.helper.layout = Layout(
    MultiField(
        'Profile Information',
        Div('first_name', 'last_name'),
        Div(css_class='clearfix'),
        Div('username', 'email'),
        Div(css_class='clearfix'),
        Div('bio', css_class='col-sm-10'),
    ),
)

I’ve tried using several different combinations of Div, Field, and Row and using combinations css_class and wrapper_class as well as trying to create "custom" attributes but nothing works to give me the layout that I want. I’ve even tried several different combinations of nested Div(Field) type structures but nothing worked.

There doesn’t seem to be a way to dynamically change the helper.field_class for just the “Bio” field row. It seems really wrong to resort to using the HTML method but that’s all I can think to do for this as this point.

What is the right way to do this using crispy-forms?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
andrewmo
  • 1,922
  • 1
  • 17
  • 20

2 Answers2

0

I have a similar function (designed for bootstrap 2) that gets you part of the way there; it doesn't work with horizontal-forms like you requested, but you are able to generate dynamic rows:

from crispy_forms import helper
from crispy_forms import layout

def addBootstrapRow(helper, firstField, numFields, wrapperClasses):

        # set classes used for all fields if only one provided
        if type(wrapperClasses) in [str, unicode]:
            wrapperClasses = [wrapperClasses]*numFields

        # find first field, apply wrapper_class for each
        first = helper.layout.index(firstField)
        for i, cls in enumerate(wrapperClasses):
            helper[first+i].wrap(layout.Field, wrapper_class=cls)

        # put all these fields into a row
        helper[first:first+numFields].wrap_together(layout.Div, css_class="row-fluid")

To get a format similar (but not identical) to the one in your question, you can do this:

class MyForm(ModelForm):

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.helper = helper.FormHelper(self)
        addBootstrapRow(self.helper, 'first_name', 2, "span6")  # all fields same
        addBootstrapRow(self.helper, 'username', 2, ["span4", "span8"])  # fields diff.
        addBootstrapRow(self.helper, 'bio', 1, "span12")

Might not your exact solution, it may help others that stumble upon this question at least (like me).

shapiromatron
  • 569
  • 6
  • 11
0

Problem

From what I have found, there isn't any simple solution to this problem.

In 2014, a GitHub issue regarding setting the label_class individually for each field was created. However, this issue was closed by the crispy forms developers as out-of-scope.

In 2021, a GitHub pull request with changes allowing label_class and field_class on individual fields was created. However, this PR was closed due to inactivity of the PR author.

Possible solutions

The answers in this question may help you with the problem. One possible solution could be to create a custom field template - see this answer.

Jakub Holan
  • 303
  • 1
  • 8