Django is one of the most popular Python frameworks for building web applications quickly and efficiently. One of its most powerful features is the built-in forms framework, which allows developers to handle user input with ease. Forms are essential in almost every web application—whether it’s for user registration, login, submitting feedback, or uploading files. Django’s form system not only helps with HTML form generation but also with data validation, error handling, and security.
In this tutorial, we’ll explore how to create a simple Django form from scratch. We’ll discuss the fundamentals of Django’s forms
module, how to display the form in templates, handle form submissions in views, validate user input, and store form data if needed. By the end of this post, you’ll have a solid understanding of how to use Django forms to collect and manage user data.
1. Understanding Django Forms
Forms are the bridge between user input and your server-side logic. In a typical web application, users fill in forms—like login fields, registration forms, or feedback boxes—and submit them to the server. The server processes this data, validates it, and performs the necessary actions.
In Django, you can build forms in two main ways:
- Using
forms.Form
– This is used for simple, non-model-based forms. You define all fields manually. - Using
forms.ModelForm
– This automatically generates form fields from a Django model, useful for database-driven forms.
In this guide, we’ll focus on the first approach, creating a form using forms.Form
, which gives you full control over field definitions and validation.
2. Setting Up a Django Project
Before we can start creating forms, you need a Django project. Let’s go through the setup quickly.
Step 1: Install Django
If you don’t already have Django installed, install it using pip:
pip install django
Step 2: Create a New Django Project
Run the following command to create a new project:
django-admin startproject formproject
This will create a directory structure like this:
formproject/
manage.py
formproject/
__init__.py
settings.py
urls.py
wsgi.py
Step 3: Create an App
Inside your project, create a new app called contact
:
python manage.py startapp contact
Your project structure should now look like:
formproject/
manage.py
formproject/
settings.py
urls.py
contact/
__init__.py
admin.py
apps.py
models.py
tests.py
views.py
Add the new app to your INSTALLED_APPS
in formproject/settings.py
:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'contact', # Our new app
]
Now we’re ready to create our first Django form.
3. Creating a Simple Django Form
We’ll create a contact form where users can enter their name, email, and a message. Django’s forms
module makes this process simple and clean.
Step 1: Create a forms.py
File
Inside your contact
app, create a new file named forms.py
and add the following code:
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100, label='Your Name')
email = forms.EmailField(label='Your Email')
message = forms.CharField(widget=forms.Textarea, label='Your Message')
This code defines a simple form with three fields:
- name: A
CharField
that accepts text input, limited to 100 characters. - email: An
EmailField
that automatically validates email format. - message: A
CharField
that uses aTextarea
widget for multi-line input.
Step 2: How Django Forms Work
Each field in a Django form is represented by a class (like CharField
, EmailField
, etc.). These fields come with built-in validation and error handling. When a user submits a form, Django can automatically check if the submitted data matches the expected types and formats.
For example:
- If the email entered isn’t valid, Django will automatically generate an error message.
- If the name field is empty, it will also raise a validation error.
4. Creating the View
Next, let’s create a view to handle the form display and submission. Open contact/views.py
and add the following:
from django.shortcuts import render
from .forms import ContactForm
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Process the form data
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = form.cleaned_data['message']
# For now, we’ll just print it to the console
print(f"Received message from {name} ({email}): {message}")
# You can add database saving, email sending, etc. here
return render(request, 'contact/success.html', {'name': name})
else:
form = ContactForm()
return render(request, 'contact/contact.html', {'form': form})
Explanation:
- If the request method is
POST
, it means the form was submitted. - We create an instance of
ContactForm
using the posted data:ContactForm(request.POST)
. - The
is_valid()
method checks if the form data passes all validation rules. - The
cleaned_data
dictionary gives access to the validated input. - If valid, you can process the data (save it, send an email, etc.).
- Otherwise, the empty form is displayed.
5. Setting Up URLs
Now, connect the view to a URL so users can access the form. In your contact
app, create a file named urls.py
:
from django.urls import path
from . import views
urlpatterns = [
path('', views.contact_view, name='contact'),
]
Then include this in your project’s main urls.py
:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('contact/', include('contact.urls')),
]
Now if you visit http://127.0.0.1:8000/contact/
, Django will display your contact form once we create the template.
6. Creating Templates
Step 1: Create Template Directory
Inside your contact
app, create a folder named templates/contact/
and add two HTML files:
contact.html
success.html
Your structure:
contact/
templates/
contact/
contact.html
success.html
Step 2: Add the Form Template
In contact/templates/contact/contact.html
, add:
<!DOCTYPE html>
<html>
<head>
<title>Contact Form</title>
</head>
<body>
<h1>Contact Us</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Send</button>
</form>
</body>
</html>
Step 3: Success Page
In contact/templates/contact/success.html
:
<!DOCTYPE html>
<html>
<head>
<title>Success</title>
</head>
<body>
<h1>Thank you, {{ name }}!</h1>
<p>Your message has been sent successfully.</p>
</body>
</html>
Now, when you submit the form, you’ll be redirected to the success page.
7. Understanding Form Validation
Form validation ensures that the submitted data meets the required criteria. Django automatically validates fields based on their type and options:
required=True
means the field cannot be empty.EmailField
checks if the value looks like a valid email.max_length
ensures text fields do not exceed the specified character limit.
If validation fails, Django automatically displays error messages next to the invalid fields in the form.
You can also add custom validation by defining a method like:
def clean_name(self):
name = self.cleaned_data.get('name')
if "@" in name:
raise forms.ValidationError("Name cannot contain @ symbol.")
return name
This method will be called automatically during validation.
8. Customizing Form Appearance
Django’s default form rendering ({{ form.as_p }}
) is simple but not very stylish. You can customize how forms are rendered using HTML.
Instead of {{ form.as_p }}
, you can render fields manually:
<form method="post">
{% csrf_token %}
<p>
{{ form.name.label_tag }}<br>
{{ form.name }}
{{ form.name.errors }}
</p>
<p>
{{ form.email.label_tag }}<br>
{{ form.email }}
{{ form.email.errors }}
</p>
<p>
{{ form.message.label_tag }}<br>
{{ form.message }}
{{ form.message.errors }}
</p>
<button type="submit">Send</button>
</form>
You can also add CSS classes in the form definition:
class ContactForm(forms.Form):
name = forms.CharField(
max_length=100,
widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter your name'})
)
email = forms.EmailField(
widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Enter your email'})
)
message = forms.CharField(
widget=forms.Textarea(attrs={'class': 'form-control', 'placeholder': 'Write your message'})
)
This is particularly useful when integrating with frameworks like Bootstrap or Tailwind CSS.
9. Handling Form Data
Once your form is validated, you can decide what to do with the submitted data. Common options include:
- Sending an email notification
- Saving data to the database
- Logging it for admin review
Here’s an example of sending an email:
from django.core.mail import send_mail
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = form.cleaned_data['message']
send_mail(
subject=f"Message from {name}",
message=message,
from_email=email,
recipient_list=['[email protected]'],
)
10. Using Django Messages Framework
Instead of redirecting to a new page after submission, you can use Django’s messages framework to show a success message on the same page.
In views.py
:
from django.contrib import messages
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
messages.success(request, 'Your message has been sent successfully!')
form = ContactForm() # reset the form
else:
form = ContactForm()
return render(request, 'contact/contact.html', {'form': form})
And in your template:
{% if messages %}
{% for message in messages %}
<p style="color: green;">{{ message }}</p>
{% endfor %}
{% endif %}
11. Adding CSRF Protection
Django automatically protects forms from Cross-Site Request Forgery (CSRF) attacks. The {% csrf_token %}
tag is essential inside every <form>
element in your templates. Django checks this token on each POST request to ensure the request originated from your site.
12. Testing Your Form
Testing forms is an important step to ensure they behave as expected. Django provides a powerful testing framework.
Example test in contact/tests.py
:
from django.test import TestCase
from .forms import ContactForm
class ContactFormTest(TestCase):
def test_valid_data(self):
form = ContactForm({
'name': 'Alice',
'email': '[email protected]',
'message': 'Hello, Django!'
})
self.assertTrue(form.is_valid())
def test_blank_data(self):
form = ContactForm({})
self.assertFalse(form.is_valid())
self.assertEqual(len(form.errors), 3)
This ensures that valid data passes and blank data fails validation.
13. Extending the Form
You can extend the ContactForm
by adding more fields:
phone = forms.CharField(required=False)
subject = forms.CharField(max_length=200)
You can also add choices fields for dropdowns:
TOPIC_CHOICES = [
('general', 'General Inquiry'),
('support', 'Support'),
('feedback', 'Feedback'),
]
topic = forms.ChoiceField(choices=TOPIC_CHOICES)
14. Security Considerations
When dealing with user input, always be aware of:
- Validation: Never trust raw input. Always validate with Django’s form system.
- CSRF protection: Always include
{% csrf_token %}
in forms. - XSS prevention: Django auto-escapes user input in templates.
- Spam protection: For public forms, consider adding CAPTCHA (e.g., reCAPTCHA).
15. Common Mistakes and Troubleshooting
1. Form not displaying:
Check that your template path is correct and that it’s included in the view’s render()
call.
2. CSRF token missing:
Always include {% csrf_token %}
inside the form.
3. Form not validating:
Check if you’re using request.POST
properly and that the form’s fields match the HTML input names.
4. Not seeing errors:
Display {{ form.errors }}
in your template to see what went wrong.
Leave a Reply