I’ve built many forms, but integrating Django with Bootstrap has always been my go-to approach for clean, responsive, and user-friendly forms. If you want to create a sleek contact form for your Django app that looks great on all devices, you’re in the right place.
In this tutorial, I’ll walk you through how to build a fully functional contact form in Django using Bootstrap. I’ll share complete code examples and explain each step clearly so you can follow along easily, even if you’re just starting with Django or Bootstrap.
Methods to Build a Contact Form in Django Using Bootstrap
Now, I will explain to you the methods to build a contact Form in Django using Bootstrap.
Read Django Programming Error: Column does not exist.
Method 1: Build a Basic Contact Form with Django Forms and Bootstrap
Step 1: Set Up Your Django Project and App
If you haven’t already created a Django project, run:
django-admin startproject myproject
cd myproject
python manage.py startapp contactAdd the contact app to your INSTALLED_APPS in settings.py:
INSTALLED_APPS = [
# other apps
'contact',
]Step 2: Create the Contact Form Using Django’s forms.Form
In contact/forms.py, define your contact form fields:
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100, widget=forms.TextInput(attrs={
'class': 'form-control', 'placeholder': 'Your Name'
}))
email = forms.EmailField(widget=forms.EmailInput(attrs={
'class': 'form-control', 'placeholder': 'Your Email'
}))
subject = forms.CharField(max_length=200, widget=forms.TextInput(attrs={
'class': 'form-control', 'placeholder': 'Subject'
}))
message = forms.CharField(widget=forms.Textarea(attrs={
'class': 'form-control', 'placeholder': 'Your Message', 'rows': 5
}))Here, I added Bootstrap classes directly to the widgets to ensure the form looks good without extra CSS.
Step 3: Create the View to Handle the Form
In contact/views.py:
from django.shortcuts import render, redirect
from django.core.mail import send_mail
from .forms import ContactForm
from django.conf import settings
from django.contrib import messages
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
full_message = f"Message from {name} <{email}>:\n\n{message}"
send_mail(
subject,
full_message,
settings.DEFAULT_FROM_EMAIL,
[settings.DEFAULT_FROM_EMAIL], # Send to your email
fail_silently=False,
)
messages.success(request, 'Your message has been sent successfully!')
return redirect('contact')
else:
form = ContactForm()
return render(request, 'contact/contact.html', {'form': form})Make sure you configure your email settings in settings.py for send_mail to work. For example, using Gmail SMTP:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'your_email@gmail.com'
EMAIL_HOST_PASSWORD = 'your_password'
DEFAULT_FROM_EMAIL = EMAIL_HOST_USERStep 4: Create the Template with Bootstrap
Create a folder contact/templates/contact/ and inside it, create contact.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Contact Us</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="container mt-5">
<h2>Contact Us</h2>
<hr>
{% if messages %}
{% for message in messages %}
<div class="alert alert-success">{{ message }}</div>
{% endfor %}
{% endif %}
<form method="post" novalidate>
{% csrf_token %}
<div class="mb-3">
{{ form.name.label_tag }}
{{ form.name }}
{% for error in form.name.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
</div>
<div class="mb-3">
{{ form.email.label_tag }}
{{ form.email }}
{% for error in form.email.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
</div>
<div class="mb-3">
{{ form.subject.label_tag }}
{{ form.subject }}
{% for error in form.subject.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
</div>
<div class="mb-3">
{{ form.message.label_tag }}
{{ form.message }}
{% for error in form.message.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
</div>
<button type="submit" class="btn btn-primary">Send Message</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>Step 5: Add URL Configuration
In contact/urls.py:
from django.urls import path
from .views import contact_view
urlpatterns = [
path('', contact_view, name='contact'),
]And include it in your project’s main urls.py:
from django.urls import path, include
urlpatterns = [
# other paths
path('contact/', include('contact.urls')),
]You can see the output in the screenshot below.

Check out Integrity Error in Django
Method 2: Use Django Crispy Forms for Cleaner Bootstrap Integration
While the above method works well, manually adding Bootstrap classes to every form field can get tedious. I recommend using the Django Crispy Forms package for better maintainability.
Step 1: Install Django Crispy Forms
pip install django-crispy-formsAdd it to your INSTALLED_APPS in settings.py:
INSTALLED_APPS = [
# other apps
'crispy_forms',
]
CRISPY_TEMPLATE_PACK = 'bootstrap5'Step 2: Update Your Form
In forms.py, remove the manual widget classes:
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
subject = forms.CharField(max_length=200)
message = forms.CharField(widget=forms.Textarea)Step 3: Update Your Template
Modify contact.html to use Crispy Forms tags:
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Contact Us</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="container mt-5">
<h2>Contact Us</h2>
<hr>
{% if messages %}
{% for message in messages %}
<div class="alert alert-success">{{ message }}</div>
{% endfor %}
{% endif %}
<form method="post" novalidate>
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Send Message</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>You can see the output in the screenshot below.

This will automatically render your form fields with Bootstrap 5 styles without manually adding CSS classes.
Read Python Django “Template does not exist” error
Tips for Production Use
- Always validate user input carefully.
- Use Django’s built-in security features like CSRF tokens (already included in the example).
- Configure your email backend securely. For production, avoid storing email passwords directly in
settings.pyuse environment variables or secret managers. - Consider adding CAPTCHA to prevent spam submissions.
- Customize your success and error messages for a better user experience.
Building a contact form in Django using Bootstrap doesn’t have to be complicated. Whether you prefer the manual approach or leveraging Django Crispy Forms, both methods help you create responsive, clean forms quickly.
Try implementing this in your next Django project and enjoy the seamless integration of backend power with frontend elegance.
You may also read:
- Python Django “Module not found” error.
- Query in Descending and Ascending in Python Django
- Parse JSON in Python Django

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.