Aditya
Aditya

Reputation: 986

How to add custom styling to Forms created with Django CreateView

I am very new to Django. Following some tutorials I have managed to create a form using the Python Generic Views (CreateView)

I have a 'Question' Model

class Question(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField(max_length=2000)
    category = models.CharField(max_length=50)
    votes = models.IntegerField(default=0)
    asked_date = models.DateTimeField(default=datetime.now)

and using this model I have created a View Class

class QuestionCreate(CreateView):
    model = Question
    fields = ['title', 'body', 'category']

This does generate a nice HTML form. But how do I pass CSS attributes to each field?

Upvotes: 5

Views: 6744

Answers (5)

zaidfazil
zaidfazil

Reputation: 9235

You could write a model form for Question and pass it to the create view,

class QuestionForm(forms.ModelForm):

    class Meta:
        model = Question
        fields = ('myfield1', 'myfield2) 
        widgets = {
        'myfield1': forms.TextInput(attrs={'class': 'myfieldclass'}),
        }

or you could override init method for specifying a certain class for every field,

def __init__(self, *args, **kwargs):
    super(QuestionForm, self).__init__(*args, **kwargs)
    self.fields['myfield1'].widget.attrs.update({'class' : 'myfieldclass'})

Then, pass it to the attribute form_class of CreateView,

class QuestionCreate(CreateView):
    model = Question
    form_class = QuestionForm

Upvotes: 13

DeepBlue
DeepBlue

Reputation: 448

The best way is to override the get_form function.

class QuestionCreate(CreateView):
    model = Question
    fields = ['title', 'body', 'category', 'MyField']

    def get_form(self, form_class=None):
        form = super(QuestionCreate, self).get_form(form_class)
        form['MyField'].field.widget.attrs.update({'class' : 'MyClass'})
        return form

Or if you want to add the attribute to all fields you can use a for-loop as follows:

class QuestionCreate(CreateView):
    model = Question
    fields = ['title', 'body', 'category', 'MyField']

    def get_form(self, form_class=None):
        form = super(OPCCreateView, self).get_form(form_class)
        for visible in form.visible_fields():
            visible.field.widget.attrs.update({'class' : 'MyClass'})
        return form

Upvotes: 2

Sal Borrelli
Sal Borrelli

Reputation: 2526

I had a similar problem in my Django application based on the Bootstrap framework. My first attempt:

# views.py
from django.views.generic.edit import UpdateView
from . import models

class ModuleUpdateView(UpdateView):
    model = models.Module
    fields = ['name', 'description', 'status']

looked as follow:

First attempt

Not very nice indeed! The second attempt implied defining a custom ModelForm for my view and applying all the customisations therein:

# forms.py
from .models import Module

class ModuleForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(ModuleForm, self).__init__(*args, **kwargs)
        for visible in self.visible_fields():
            visible.field.widget.attrs['class'] = 'form-control'

    class Meta:
        model = Module
        fields = ['name', 'description', 'status']

Please note the for cycle in __init__, which adds the form-control CSS class to all visible form fields. The CSS styling for form-control is provided by Bootstrap so I didn't even have to modify my stylesheets.

Once I have my custom ModelForm I can rewrite my View class as follows:

# views.py
from django.views.generic.edit import UpdateView
from . import forms, models

class ModuleUpdateView(UpdateView):
    model = models.Module
    form_class = forms.ModuleForm

and you can see the results below.

Second attempt

Far better!

Hope that helps, feel free to comment in case of questions.

Upvotes: 7

allenjiji
allenjiji

Reputation: 1

We can use django-crispy-forms if we want some bootstrap styling to the rendered form:

pip install django-crispy-forms

Then add 'crispy-forms' to the installed apps.
Load the crispy_form_tags in the form template page and instead of {{form}} use {{form|crispy}}.

Documentation of Crispy.

Upvotes: 0

Exprator
Exprator

Reputation: 27513

class FooForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(FooForm, self).__init__(*args, **kwargs)
        self.fields['field1'].widget.attrs = { 'class': 'fooclass' }

    class Meta:
        model = FooModel
        fields = ['field1', 'field2']

you cannot directly add css to the CreateView for that you need to create a ModelForm and use the form_class = FooForm in your create view, and in this ModelForm you can use specific class for the fields and use css to style them as needed

Upvotes: 4

Related Questions