Skip to content

Chapter 8: Django Forms

8.1 Form Basics

Form Class Definition

The Django form system provides a powerful and flexible way to handle HTML forms. Form classes inherit from django.forms.Form and are used to define form fields and validation logic.

Basic form class definition:

python
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)

Form Field Types

Django provides multiple built-in form field types, each with specific validation rules:

python
from django import forms
from django.core.validators import RegexValidator

class ExampleForm(forms.Form):
    # String field
    name = forms.CharField(
        max_length=100,
        min_length=2,
        label='Name',
        help_text='Please enter your real name'
    )
    
    # Email field
    email = forms.EmailField(
        label='Email Address',
        help_text='Please enter a valid email address'
    )
    
    # Integer field
    age = forms.IntegerField(
        min_value=0,
        max_value=150,
        label='Age'
    )
    
    # Float field
    salary = forms.FloatField(
        min_value=0,
        label='Salary'
    )
    
    # URL field
    website = forms.URLField(
        required=False,
        label='Personal Website'
    )
    
    # Date field
    birth_date = forms.DateField(
        label='Birth Date',
        widget=forms.DateInput(attrs={'type': 'date'})
    )
    
    # DateTime field
    appointment = forms.DateTimeField(
        label='Appointment Time'
    )
    
    # Boolean field
    subscribe = forms.BooleanField(
        required=False,
        label='Subscribe to Email'
    )
    
    # Choice field
    GENDER_CHOICES = [
        ('male', 'Male'),
        ('female', 'Female'),
        ('other', 'Other')
    ]
    gender = forms.ChoiceField(
        choices=GENDER_CHOICES,
        label='Gender'
    )
    
    # Multiple choice field
    INTERESTS_CHOICES = [
        ('tech', 'Technology'),
        ('sports', 'Sports'),
        ('music', 'Music'),
        ('travel', 'Travel')
    ]
    interests = forms.MultipleChoiceField(
        choices=INTERESTS_CHOICES,
        widget=forms.CheckboxSelectMultiple,
        label='Interests'
    )
    
    # File field
    avatar = forms.ImageField(
        required=False,
        label='Avatar'
    )
    
    # Custom validation field
    phone = forms.CharField(
        validators=[RegexValidator(
            regex=r'^\+?1?\d{9,15}$',
            message="Please enter a valid phone number"
        )],
        label='Phone Number'
    )

Form Validation

Django forms provide multiple validation mechanisms:

  1. Field-level validation
  2. Form-level validation
  3. Custom validation methods
python
from django import forms
from django.core.exceptions import ValidationError

class RegistrationForm(forms.Form):
    username = forms.CharField(max_length=150)
    email = forms.EmailField()
    password = forms.CharField(widget=forms.PasswordInput)
    password_confirm = forms.CharField(widget=forms.PasswordInput)
    
    def clean_username(self):
        """Validate if username already exists"""
        username = self.cleaned_data['username']
        if User.objects.filter(username=username).exists():
            raise ValidationError("Username already exists")
        return username
    
    def clean_email(self):
        """Validate if email already exists"""
        email = self.cleaned_data['email']
        if User.objects.filter(email=email).exists():
            raise ValidationError("Email already registered")
        return email
    
    def clean(self):
        """Form-wide validation"""
        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 ValidationError("Passwords do not match")
        
        return cleaned_data

Form Rendering

Django provides multiple ways to render forms:

html
<!-- forms.py -->
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)

<!-- views.py -->
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 form data
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            # Send email and other operations
            return render(request, 'contact_success.html')
    else:
        form = ContactForm()
    
    return render(request, 'contact.html', {'form': form})

<!-- contact.html -->
<form method="post">
    {% csrf_token %}
    
    <!-- Method 1: Manually render each field -->
    <div>
        <label for="{{ form.name.id_for_label }}">Name:</label>
        {{ form.name }}
        {% if form.name.errors %}
            <div class="error">{{ form.name.errors }}</div>
        {% endif %}
    </div>
    
    <!-- Method 2: Use form's as_p method -->
    {{ form.as_p }}
    
    <!-- Method 3: Use form's as_table method -->
    <table>
        {{ form.as_table }}
    </table>
    
    <!-- Method 4: Use form's as_ul method -->
    <ul>
        {{ form.as_ul }}
    </ul>
    
    <button type="submit">Submit</button>
</form>

<!-- Method 5: Loop through fields -->
<form method="post">
    {% csrf_token %}
    {% for field in form %}
        <div class="form-group">
            {{ field.label_tag }}
            {{ field }}
            {% if field.errors %}
                <div class="error">
                    {% for error in field.errors %}
                        <p>{{ error }}</p>
                    {% endfor %}
                </div>
            {% endif %}
            {% if field.help_text %}
                <small class="help-text">{{ field.help_text }}</small>
            {% endif %}
        </div>
    {% endfor %}
    <button type="submit">Submit</button>
</form>

Using CSS classes and attributes in templates:

python
# forms.py
class StyledForm(forms.Form):
    name = forms.CharField(
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': 'Please enter your name'
        })
    )
    email = forms.EmailField(
        widget=forms.EmailInput(attrs={
            'class': 'form-control',
            'placeholder': 'Please enter your email'
        })
    )

Through this approach, you can create a complete form system with full functionality and validation.

Summary

Django form basics are the core of web application interaction:

  1. ✅ Form classes define form structure and validation rules
  2. ✅ Multiple field types meet different data requirements
  3. ✅ Multi-level validation mechanisms ensure data validity
  4. ✅ Flexible form rendering methods
  5. ✅ Good integration with CSS frameworks like Bootstrap

Mastering form basics is the prerequisite for building user interaction features.

Next

We will learn about using ModelForm.

8.2 Model Forms →

Contents

Back to Course Outline

Released under the [BY-NC-ND License](https://creativecommons.org/licenses/by-nc-nd/4.0/deed.en).