Django Forms

Almost every website needs to collect data from users — registration forms, login forms, search boxes, contact forms. Django has a powerful built-in Forms system that handles creating HTML form fields, validating the submitted data, and showing error messages automatically.

What is a Django Form?

A Django Form is a Python class that defines what fields a form should have, what type of data each field accepts, and what rules the data must follow before being accepted. Django then renders these fields as HTML automatically and validates the submitted data for you.

Example: Imagine a bank's account opening form. A teller hands you the form (Django renders the HTML fields), you fill it in (user enters data), and the bank clerk checks each field — is the phone number valid? Is the date of birth in the right format? Is the PAN number filled in? (Django validation). If something is wrong, the clerk hands the form back with errors marked in red (Django shows error messages).

Types of Django Forms

  • forms.Form — A manually defined form, not connected to any database model. Good for contact forms, search forms, or custom use cases.
  • forms.ModelForm — A form automatically built from a model. If you have a Student model, Django can generate a form from it automatically, saving a lot of repetition.

Creating a Basic Form (forms.Form)

Create a new file called forms.py inside your app folder and define your form class:


# students/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)
    subject = forms.CharField(max_length=200, required=False)

Each attribute here is a form field. Django uses the field type to decide what HTML input to render and how to validate it.

Common Form Field Types

  • CharField — A single-line text input (renders as <input type="text">)
  • EmailField — Validates that the value looks like an email address
  • IntegerField — Accepts whole numbers only
  • BooleanField — Renders as a checkbox
  • ChoiceField — Renders as a dropdown select
  • DateField — Accepts a date in the correct format
  • FileField — Accepts a file upload

Using a Form in a View

Your view handles both showing the empty form (GET request) and processing the submitted form (POST request):


# students/views.py

from django.shortcuts import render
from .forms import ContactForm

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)      # Bind submitted data to the form
        if form.is_valid():                   # Check if all fields are valid
            name = form.cleaned_data['name']
            message = form.cleaned_data['message']
            # Do something with the data (save to DB, send email, etc.)
            return render(request, 'students/success.html', {'name': name})
    else:
        form = ContactForm()                  # Create an empty form for GET request

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

Key points in this view:

  • ContactForm(request.POST) — Creates a "bound" form with the submitted data.
  • form.is_valid() — Returns True if all fields pass validation; False if any field has an error.
  • form.cleaned_data — A dictionary of the cleaned (safe, validated) data. Always use this, not raw request.POST.
Example: is_valid() is like a security scanner at the airport. Before you board the plane (save data), everything goes through the scanner (validation). If anything suspicious is found (invalid data), you are stopped and told what needs to be fixed.

Displaying the Form in a Template

In your template, display the form using Django's template syntax:


<!-- students/templates/students/contact.html -->

<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Send Message</button>
</form>
  • {% csrf_token %}Must always be included inside every POST form. It protects your form from CSRF attacks (a type of security threat). Django will reject the form if this token is missing.
  • {{ form.as_p }} — Renders each form field wrapped in a <p> tag automatically.

Other Form Rendering Options


{{ form.as_p }}      <-- Each field in a <p> tag
{{ form.as_ul }}     <-- Each field in a <li> tag
{{ form.as_table }}  <-- Each field in a <tr> tag

Rendering Fields Individually

For more control over layout, you can render each field individually:


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

    <label>Name</label>
    {{ form.name }}
    {{ form.name.errors }}

    <label>Email</label>
    {{ form.email }}
    {{ form.email.errors }}

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

Form Validation — Built-in and Custom

Django automatically validates fields based on their type. But you can also add your own custom validation rules.

Field-level custom validation

Add a method called clean_fieldname() to validate a specific field:


class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    roll_number = forms.IntegerField()

    def clean_roll_number(self):
        roll = self.cleaned_data['roll_number']
        if roll <= 0:
            raise forms.ValidationError("Roll number must be a positive number.")
        return roll
Example: Built-in validation catches obvious errors — "this field is required" or "enter a valid email". Custom validation catches your specific business rules — "roll number must be between 1 and 500" or "username cannot contain spaces".

ModelForm — Building a Form from a Model

If you already have a model, you don't need to rewrite all the same fields in a form. Use ModelForm to generate the form automatically from the model:


# students/forms.py

from django import forms
from .models import Student

class StudentForm(forms.ModelForm):
    class Meta:
        model = Student                             # Use the Student model
        fields = ['name', 'roll_number', 'email']   # Show only these fields
        # OR use fields = '__all__' to include all fields

The view for a ModelForm works the same way, but saving is even easier:


# students/views.py

from .forms import StudentForm

def add_student(request):
    if request.method == 'POST':
        form = StudentForm(request.POST)
        if form.is_valid():
            form.save()      # <-- Saves directly to the database!
            return render(request, 'students/success.html')
    else:
        form = StudentForm()

    return render(request, 'students/add_student.html', {'form': form})

form.save() creates a new record in the database with the submitted data in one single line.

Example: ModelForm is like a pre-filled job application form generated from the HR department's requirements list. You don't design it from scratch — it's automatically created based on what the HR system (model) needs. One click saves the application directly to the HR database.

Quick Recap

  • Django Forms handle creating HTML fields, validating data, and displaying errors automatically.
  • Use forms.Form for custom forms and forms.ModelForm for forms based on a model.
  • Always include {% csrf_token %} inside every POST form template.
  • Check form.is_valid() before processing submitted data.
  • Always use form.cleaned_data to access validated form data — never use raw request.POST data directly.
  • Use form.save() in a ModelForm to save data directly to the database in one line.

Leave a Comment

Your email address will not be published. Required fields are marked *