Skip to main content

Django Forms Introduction

Forms are a crucial part of web applications, serving as the primary interface between users and your application. Django provides a powerful forms library that helps you create forms, validate input data, and process submissions efficiently. In this tutorial, we'll introduce Django forms and learn how to implement them in your projects.

What are Django Forms?

Django forms are Python classes that define a web form, including:

  • The fields it contains
  • How the fields are rendered as HTML
  • How submitted data is validated
  • How errors are displayed

Django forms handle three distinct tasks:

  1. Rendering HTML form widgets - creating the actual form elements
  2. Validating user-submitted data - ensuring inputs meet requirements
  3. Converting form data to Python types - transforming data for use in your application

Why Use Django Forms?

You might wonder, "Why not just write HTML forms directly?" Here are some benefits of using Django forms:

  • Security - Django forms protect against CSRF attacks and handle input sanitization
  • Validation - Built-in validation rules save you from writing repetitive code
  • Consistent rendering - Forms maintain a consistent look across your application
  • Reduced boilerplate - Django forms eliminate repetitive form-handling code

Creating Your First Django Form

Let's create a simple contact form. First, we need to create a new file called forms.py in our app directory:

python
# myapp/forms.py
from django import forms

class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)

In this example, we:

  1. Import Django's forms module
  2. Create a ContactForm class that inherits from forms.Form
  3. Define three fields: name (text), email (email), and message (text area)

Rendering Forms in Templates

To display this form in a template, first, pass it from your view:

python
# myapp/views.py
from django.shortcuts import render
from .forms import ContactForm

def contact_view(request):
form = ContactForm()
return render(request, 'contact.html', {'form': form})

Then, in your template:

html
<!-- contact.html -->
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Send Message</button>
</form>

Django provides several methods to render forms:

  • {{ form.as_p }} - Renders form with each field wrapped in <p> tags
  • {{ form.as_table }} - Renders form as table rows
  • {{ form.as_ul }} - Renders form fields as list items

Processing Form Submissions

To handle form submissions, update your view to process POST requests:

python
# myapp/views.py
from django.shortcuts import render, redirect
from .forms import ContactForm

def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Access cleaned data
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = form.cleaned_data['message']

# Process the data (e.g., send email)
# ...

return redirect('success')
else:
form = ContactForm()

return render(request, 'contact.html', {'form': form})

This view:

  1. Checks if the request method is POST
  2. If so, initializes the form with submitted data
  3. Validates the form using is_valid()
  4. If valid, processes the cleaned data
  5. If not (or for GET requests), creates an empty form

Form Validation and Displaying Errors

Django automatically validates forms based on field types. For example:

  • EmailField ensures valid email format
  • IntegerField ensures numeric input

Here's how errors are displayed in templates:

html
<form method="POST">
{% csrf_token %}

{% if form.errors %}
<div class="alert alert-danger">
Please correct the errors below.
</div>
{% endif %}

{% for field in form %}
<div class="form-group">
{{ field.label_tag }}
{{ field }}

{% if field.errors %}
<small class="text-danger">
{{ field.errors|join:", " }}
</small>
{% endif %}
</div>
{% endfor %}

<button type="submit">Submit</button>
</form>

Adding Custom Validation

You can add custom validation logic to your forms:

python
# myapp/forms.py
from django import forms

class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)

def clean_name(self):
"""Custom validator for the name field"""
name = self.cleaned_data.get('name')

# Check if name is all lowercase
if name.islower():
raise forms.ValidationError("Please use proper capitalization in your name.")

return name

def clean(self):
"""Validate the entire form"""
cleaned_data = super().clean()
email = cleaned_data.get('email')
name = cleaned_data.get('name')

# Example custom validation between fields
if name and email and name.lower() in email.lower():
raise forms.ValidationError(
"Email address cannot contain your name for security reasons."
)

return cleaned_data

Working with Form Widgets

Widgets control how form fields are rendered as HTML:

python
class FeedbackForm(forms.Form):
rating = forms.ChoiceField(
choices=[(1, '1 Star'), (2, '2 Stars'), (3, '3 Stars'), (4, '4 Stars'), (5, '5 Stars')],
widget=forms.RadioSelect
)
comments = forms.CharField(
widget=forms.Textarea(attrs={'rows': 5, 'placeholder': 'Enter your comments here'})
)
would_recommend = forms.BooleanField(
required=False,
widget=forms.CheckboxInput
)

Real-World Example: A Registration Form

Let's create a more practical example - a user registration form:

python
# users/forms.py
from django import forms

class UserRegistrationForm(forms.Form):
username = forms.CharField(max_length=30, min_length=4, help_text="Required. 4-30 characters.")
email = forms.EmailField(help_text="Required. A valid email address.")
password = forms.CharField(widget=forms.PasswordInput)
password_confirm = forms.CharField(widget=forms.PasswordInput, label="Confirm Password")
terms_agreement = forms.BooleanField(
required=True,
label="I agree to the terms of service"
)

def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get('password')
password_confirm = cleaned_data.get('password_confirm')

if password and password_confirm and password != password_confirm:
raise forms.ValidationError("Passwords don't match")

return cleaned_data

And the view to handle it:

python
# users/views.py
from django.shortcuts import render, redirect
from .forms import UserRegistrationForm
from django.contrib.auth.models import User
from django.contrib.auth import login

def register(request):
if request.method == 'POST':
form = UserRegistrationForm(request.POST)
if form.is_valid():
# Create user account
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)

# Log the user in
login(request, user)
return redirect('home')
else:
form = UserRegistrationForm()

return render(request, 'users/register.html', {'form': form})

Summary

Django forms provide a powerful way to handle user input in web applications. They offer:

  • Simple form creation through Python classes
  • Automatic HTML rendering
  • Built-in validation
  • Secure processing of user data

As you become more familiar with Django forms, you'll discover how they can save you time and effort while creating robust web applications.

Next Steps

Now that you understand the basics of Django forms, you might want to explore:

  • Form styling - Customizing the appearance of your forms
  • ModelForms - Forms that are automatically generated from your models
  • Form sets - Working with multiple forms at once
  • File uploads - Handling files through forms

Exercises

  1. Create a simple form with at least three different field types.
  2. Add custom validation to ensure a field doesn't contain certain words.
  3. Create a multi-step form process where data is saved across multiple pages.
  4. Style a form using CSS to improve its appearance.

Happy coding with Django forms!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)