When working with Django forms, one of the first things you'll want to do is customize how your form fields look and behave. Whether it's adding CSS classes, placeholders, or changing the type of input, Django gives you multiple ways to tweak widgets.
In this article, we'll walk through how to customize widgets in two scenarios:
- A plain vanilla form (based on
forms.Form
) - A model form (based on
forms.ModelForm
)
Let’s dive in. 🏊♂️
1. Customizing Widgets in Vanilla Forms (forms.Form
)
We have this contact form.
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField()
Options:
- Option 1: define the Widget Inline. You set the widget right inside the field definition.
- Option 2: modify a widget in the form definition.
-
Option 3: modify Widgets in
__init__
. If you need conditional logic (based on a user or some external flag), you can update the widget after instantiation.
Let's see all options in one form example:
# forms.py
class ContactForm(forms.Form):
subject = forms.CharField(
max_length=100,
# *** CUSTOMIZE WIDGET: option 1 ***
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Subject",
}
),
)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
# *** CUSTOMIZE WIDGET: option 2 ***
message.widget.attrs.update(
{"class": "form-control", "placeholder": "Write your message here"}
)
# *** CUSTOMIZE WIDGET: option 3 ***
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
self.fields["sender"].widget.attrs["class"] = "form-control"
# Conditional logic based on user
if user and user.is_authenticated:
self.fields["sender"].initial = user.email
else:
print(user)
self.fields["sender"].widget.attrs["readonly"] = True
self.fields["sender"].widget.attrs[
"placeholder"
] = "Login to fill your email"
The user is passed into the view when instantiating the form:
#views.py
def form3(request):
if request.method == "POST":
form = ContactForm(request.POST)
if form.is_valid():
context = {"form": form}
messages.success(request, "Your message has been sent!")
return redirect("form")
else:
form = ContactForm(user=request.user)
context = {"form": form}
return render(request, "form.html", context=context)
2. Customizing Widgets in Model Forms (forms.ModelForm
)
We have this form and model.
#forms.py
class PostForm(ModelForm):
class Meta:
model = Post
fields = "__all__"
# models.py
class Post(models.Model):
title = models.CharField()
title_tag = models.CharField()
body = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
You can customize the widget like this:
Options:
- Option 1: override fields manually
- Option 2: use widgets inside the Meta class
-
Option 3: modify Widgets in
__init__
. If you need conditional logic (based on a user or some external flag), you can update the widget after instantiation.
Let's see all options in one form example:
class PostForm(ModelForm):
# *** CUSTOMIZE WIDGET: option 1 ***
title = forms.CharField(
widget=forms.TextInput(
attrs={"class": "form-control", "placeholder": "Here goes the title"}
)
)
class Meta:
model = Post
fields = "__all__"
# *** CUSTOMIZE WIDGET: option 2 ***
widgets = {
"body": forms.Textarea(attrs={"class": "form-control", "rows": 5}),
}
# *** CUSTOMIZE WIDGET: option 3 ***
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["title_tag"].widget.attrs.update(
{"class": "form-control", "placeholder": "Title tag"}
)
Now you are free to customize the widgets in your project!