Creating a Simple Django Form

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:

  1. Using forms.Form – This is used for simple, non-model-based forms. You define all fields manually.
  2. 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 a Textarea 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>
&lt;title&gt;Contact Form&lt;/title&gt;
</head> <body>
&lt;h1&gt;Contact Us&lt;/h1&gt;
&lt;form method="post"&gt;
    {% csrf_token %}
    {{ form.as_p }}
    &lt;button type="submit"&gt;Send&lt;/button&gt;
&lt;/form&gt;
</body> </html>

Step 3: Success Page

In contact/templates/contact/success.html:

<!DOCTYPE html>
<html>
<head>
&lt;title&gt;Success&lt;/title&gt;
</head> <body>
&lt;h1&gt;Thank you, {{ name }}!&lt;/h1&gt;
&lt;p&gt;Your message has been sent successfully.&lt;/p&gt;
</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 %}
&lt;p&gt;
    {{ form.name.label_tag }}&lt;br&gt;
    {{ form.name }}
    {{ form.name.errors }}
&lt;/p&gt;
&lt;p&gt;
    {{ form.email.label_tag }}&lt;br&gt;
    {{ form.email }}
    {{ form.email.errors }}
&lt;/p&gt;
&lt;p&gt;
    {{ form.message.label_tag }}&lt;br&gt;
    {{ form.message }}
    {{ form.message.errors }}
&lt;/p&gt;
&lt;button type="submit"&gt;Send&lt;/button&gt;
</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&#91;'name']
email = form.cleaned_data&#91;'email']
message = form.cleaned_data&#91;'message']

send_mail(
    subject=f"Message from {name}",
    message=message,
    from_email=email,
    recipient_list=&#91;'[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 %}
    &lt;p style="color: green;"&gt;{{ message }}&lt;/p&gt;
{% 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.


Comments

Leave a Reply

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