17

I'm using django-crispy-forms with Twitter Bootstrap , and I'm having some issues with customizing my forms into multiple rows and columns. One example problem is that nothing happens when I try to split the form into two columns:

class SomeForm(ModelForm):

    helper = FormHelper()
    helper.layout = Layout(
        Column('field1', 'field3'),
        Column('field2', 'field4'),
        )
    )

    class Meta:
        model = Model

Looking at the html output, I see that there is the <div class="formColumn">, but the form is displayed in one single column. Maybe is this an css issue? I am using Bootstrap 2.1.

4 Answers 4

36

Thanks maraujo.

I've achieved this using the div tag and the bootstrap docs: http://twitter.github.com/bootstrap/scaffolding.html

class SomeForm(ModelForm):

    helper = FormHelper()
    helper.layout = Layout(
        Div(
            Div('field1', css_class='span6'),
            Div('field3', css_class='span6'),  
        css_class='row-fluid'), 
    )

    class Meta:
        model = Model

For bootstrap3 replace span6 with col-xs-6 http://getbootstrap.com/css/#grid

Sign up to request clarification or add additional context in comments.

5 Comments

Nice one, I will write this down in the docs for other people, it's a good practice.
@maraujop If I want an actual <table> which template should I override? I can't seem to find it.
Crispy doesn't do table layouts, and neither should you. HTML table layouts have been deprecated for at least a decade now.
For bootstrap3 also replace 'row-fluid' with 'row'
For bootstrap4 see @pepjin answer below
18

Small 2018 update on the answer by martinpaulucci:

For Bootstrap 4 and latest django-crispy-forms 1.7.2 use:

class SomeForm(ModelForm):

    helper = FormHelper()
    helper.layout = Layout(
        Div(
            Field('field1', wrapper_class='col-md-3'),
            Field('field3', wrapper_class='col-md-9'),  
        css_class='form-row') 
    )

    class Meta:
        model = Model

The use of the Field tag in stead of the Div tag avoids another unnecessary wrapper div. To improve on that you can replace crispy-forms Row with your own if you're going to use more than one row:

class Row(Div):
    css_class = "form-row"

then use:

class SomeForm(ModelForm):

    helper = FormHelper()
    helper.layout = Layout(
        Row(
            Field('field1', wrapper_class='col-md-3'),
            Field('field3', wrapper_class='col-md-9')  
        ) 
    )

    class Meta:
        model = Model

2 Comments

Where does the overriding row class go?
You can put it somewere in the same file before your form class.
6

June 2022 Update on the answer by martinpaulucci and Pepijn:
For Bootstrap 5 and django-crispy-forms 1.14.0, css_class = "form-row" no longer works. Instead use 'row':

class Row(Div):
    css_class = 'row'

Here's an example implementation using the Row class defined by Pepijn above (forms.py):

class Row(Div):
    css_class = 'row g-3'

class BlogUserCreationForm(UserCreationForm):
    """
    Create a custom user creation form using the custom BlogUser user model.
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(
            Row(
                Field('username', wrapper_class='form-group col-md-6 mb-0'),
                Field('email', wrapper_class='form-group col-md-6 mb-0'),
            ),
            'password1',
            'password2',
            Row(
                Field('first_name', wrapper_class='form-group col-md-4 mb-0'),
                Field('last_name', wrapper_class='form-group col-md-4 mb-0'),
                Field('date_born', wrapper_class='form-group col-md-4 mb-0'),
            ),
            'short_bio',
            Submit('submit', 'Submit')
        )

    class Meta:
        model = BlogUser
        fields = ("username", 'email', 'password1', 'password2', 'first_name', 'last_name', 'date_born', 'short_bio')

(I added 'g-3' to my css_class in the implementation to add gutters between the rows).

In case anyone is curious, in my settings.py the crispy_template_pack is still defined as bootstrap4 as per the docs; however, bootstrap5 still seems to work with django-crispy-forms so far as I've found.

CRISPY_TEMPLATE_PACK = 'bootstrap4'

Comments

3

Had issue with Django3 + ModelForm displaying multiple fields on the same row like this

def __init__(self, *args, **kwargs):
    super(SupplierDetailForm, self).__init__(*args, **kwargs)

    self.helper = FormHelper(self)
    self.helper.layout = Layout(
        Row(
            Column('nom', css_class='form-group col-2 mb-0'),
            Column('email', css_class='form-group col-4 mb-0'),
        )
    )

I noticed that Crispy "row" class is in fact a "form-row" class that doesn't match with Bootstrap 4 classes.

Pepijn's tip did the job. Thanks

2 Comments

Please don't add "thank you" as an answer. Once you have sufficient reputation, you will be able to vote up questions and answers that you found helpful. - From Review
This should be the accepted answer. Awesome, thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.