When customizing Django forms, you usually have to add it on the forms definition using the widget. Say for example you want to add a class attribute...
Awesome forms with django-crispy-forms
Django-crispy-forms is a third-party Django application which lets you create beautiful forms in “a very elegant and DRY way”. Best of all—you don’t need to code form templates unless you really want to. The resulting form markup, by default, is compatible with Twitter Bootstrap 2. If you want to use Bootstrap …
Django-crispy-forms is a third-party Django application which lets you create beautiful forms in “a very elegant and DRY way”. Best of all—you don’t need to code form templates unless you really want to.
The resulting form markup, by default, is compatible with Twitter Bootstrap 2. If you want to use Bootstrap 3 to render your forms, add the following setting to your settings.py:
CRISPY_TEMPLATE_PACK = 'bootstrap3'
To give a brief demonstration of what `django-crispy-forms` can do, let us try creating a user profile form in Django.
We begin with a simple user model:
class User(AbstractUser): COUNTRIES = () # Contents are left as an exercise to the reader # Address address1 = models.CharField(max_length=50) address2 = models.CharField(max_length=50) city = models.CharField(max_length=50) state = models.CharField(max_length=50) country = models.CharField(max_length=50, choices=COUNTRIES) # Contact mobile = models.CharField(max_length=32) home = models.CharField(max_length=32) office = models.CharField(max_lenghth=32) twitter = models.CharField(max_length=100) def __unicode__(self): return self.username
This example works with custom user models available since Django 1.5.
At this point, we will create a form that will correspond with this model. Something like this perhaps?
from django import forms class UserForm(forms.ModelForm): class Meta: model = User # Your User model
This cannot be written more concisely, don’t you think?
Now we’ll see what happens when you try to render this form in a template.
<form action="" method="POST"> <input type="submit" value="Submit"> </form>
Looks simple enough, until you need to skin the form, adjust the layout for each field, group the fields into categories, and so on. The form template will get complicated very quickly. I am sure you get what I mean.
Adding crispy-forms to the mix
To use `django-crispy-forms`, you will need to install the app via `pip`, and then add `crispy_forms` in your `INSTALLED_APPS` setting.
The simplest crispy-forms form will not require you to make any changes to the model form class. The template will need to change, however:
Running your project and viewing the rendered template, what you will see is a beautifully rendered form (especially if you are using Twitter Bootstrap), without using any tables or lists. The form tags and the CSRF token are already added for your benefit.
The best thing about `crispy-forms` is the form helper, defined under your form as the `helper` attribute. Anything you need to define in the form, like the form’s action, method and even layout are set in the helper. No need to go back and forth between your form class and any template that use the form!
Say we don’t want crispy-forms automatically adding the form tag. This scenario happens when your template is composed of several forms under a single form tag. You will need to set form_tag to False in the helper.
from django import forms from crispy_forms.helper import FormHelper class UserForm(forms.ModelForm): helper = FormHelper() helper.form_tag = False class Meta: model = User # Your user model
You will also need to change the template to define the form tag yourself:
<form action="" method="POST"> </form>
This scenario may be more common on your project; if so, go ahead and use this mixin:
from django import forms from crispy_forms.helper import FormHelper class NoFormTagCrispyFormMixin(object): @property def helper(self): if not hasattr(self, '_helper'): self._helper = FormHelper() self._helper.form_tag = False return self._helper
Customizing your form’s layout
Let’s say you need to need to have address and contact information in their own tabs in the template. Even using Twitter Bootstrap, you will find that you will need to do a lot of HTML coding in order to accomplish this task.
Using crispy-forms will simplify this task for you. What you do is define the form’s `layout` in the helper. Like so:
from django import forms from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout from crispy_forms.bootstrap import TabHolder, Tab class UserForm(forms.ModelForm): helper = FormHelper() helper.form_tag = False helper.layout = Layout( TabHolder( Tab( 'Basic Information', 'first_name', 'last_name' ), Tab( 'Address', 'address1', 'address2', 'city', 'state', 'country' ), Tab( 'Contact', 'email', 'mobile', 'home', 'office', 'twitter' ) ) ) class Meta: model = User # Your User model
You do not need to make any additional changes to the template. Note, however, that the fields you include in the layout must match the fields that your form will be expecting.
Run your project and behold, your user profile form, all set, looking pretty.
There are a lot more customization options available in django-crispy-forms. Head over to the documentation and read all about it.