Open In App

Handle Multiple Forms on a Single Page in Django

Last Updated : 02 Jul, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

One common scenario in web development is handling multiple forms on a single page. This might be required when a user needs to fill out various types of information without navigating away from the page. In this article, we will explore the best practices for managing multiple forms on a single page in Django, including structuring our HTML template, handling form submissions, and validating user input.

How to Manage Multiple Forms in Django

When dealing with multiple forms on a single page, it's crucial to understand how Django's forms system can handle multiple instances simultaneously. Each form should be uniquely identified, and we need to ensure that the server correctly processes each form's data. Typically, forms are used for different purposes, such as creating or updating records. Properly distinguishing between these forms is essential for accurate data processing.

Step-by-Step Integration :

Let's create a Django project that handles multiple forms with a creative and functional design. We’ll include two forms with different fields, ensure that they are styled nicely, and handle form submissions effectively.

1. Create a Django Project and App:

django-admin startproject myproject
cd myproject
python manage.py startapp myapp

Add myapp to the INSTALLED_APPS in settings.py:

Python
# ...
INSTALLED_APPS = [
    # ... other installed apps
    'myapp',
]

And add the following piece of code too in "settings.py" to link css to the project:

Python
# settings.py

STATIC_URL = '/static/'

# Make sure this is set correctly
STATICFILES_DIRS = [BASE_DIR / "myapp/static"]

# This tells Django to serve the static files during development
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'

The project Structure should look something like this:

Screenshot-from-2024-09-20-10-41-36
fig: File Structure

Note: We will add the html file later in the templates directory.

2. Define Models

In myapp/models.py file, let's create two models:

Python
# myapp/models.py
from django.db import models

class Form1Model(models.Model):
    field1 = models.CharField(max_length=100)
    field2 = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.field1} - {self.field2}"

class Form2Model(models.Model):
    field3 = models.CharField(max_length=100)
    field4 = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.field3} - {self.field4}"

To apply these models to the database let's run migrations and migrate commands:

python manage.py makemigrations
python manage.py migrate

3. Define Forms:

In 'myapp/forms.py', let's create two forms that will take input strings of minimum length 5:

Python
from django import forms
from .models import Form1Model, Form2Model
class Form1(forms.ModelForm):
    class Meta:
        model = Form1Model
        fields = ['field1', 'field2']
    def clean_field1(self):
        field1 = self.cleaned_data.get('field1')
        if len(field1) < 5:
            raise forms.ValidationError("Field 1 must be at least 5 characters long.")
        return field1
class Form2(forms.ModelForm):
    class Meta:
        model = Form2Model
        fields = ['field3', 'field4']
    def clean_field3(self):
        field3 = self.cleaned_data.get('field3')
        if len(field3) < 5:
            raise form

4. Create a View to Handle Form Submission:

In 'myapp/views.py', define a view that handles both forms:

Python
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import Form1, Form2
from .models import Form1Model, Form2Model

def handle_forms(request):
    form1 = Form1(prefix='form1')
    form2 = Form2(prefix='form2')
    if request.method == 'POST':
        if 'submit_form1' in request.POST:
            form1 = Form1(request.POST, prefix='form1')
            if form1.is_valid():
                form1.save()
                messages.success(request, 'Form 1 submitted successfully.')
                return redirect('handle-forms')
            # Keep form2 unchanged if form1 is submitted
        elif 'submit_form2' in request.POST:
            form2 = Form2(request.POST, prefix='form2')
            if form2.is_valid():
                form2.save()
                messages.success(request, 'Form 2 submitted successfully.')
                return redirect('handle-forms')
            # Keep form1 unchanged if form2 is submitted
    form1_data = Form1Model.objects.all()
    form2_data = Form2Model.objects.all()
    return render(request, 'myapp/forms_template.html', {
        'form1': form1,
        'form2': form2,
        'form1_data': form1_data,
        'form2_data': form2_data,
    })

4. Create a Template to Render Forms:

Create a template 'myapp/templates/myapp/my_template.html' and create a 'static/css/styles.css' file in 'myapp' directory to display and handle form submissions:

HTML
<!-- myapp/templates/myapp/my_template.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Multiple Forms</title>
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head>
<body>
    <div class="container">
        <h1>Form 1</h1>
        <form method="post" class="form">
            {% csrf_token %}
            {{ form1.as_p }}
            {% if form1.errors %}
                <div class="error">
                    <p>Please correct the errors below:</p>
                    <ul>
                        {% for error in form1.errors %}
                        <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                </div>
            {% endif %}
            <button type="submit" class="btn">Submit Form 1</button>
        </form>

        <h2>Form 1 Data</h2>
        <table class="data-table">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Field 1</th>
                    <th>Field 2</th>
                    <th>Created At</th>
                </tr>
            </thead>
            <tbody>
                {% for item in form1_data %}
                <tr>
                    <td>{{ item.id }}</td>
                    <td>{{ item.field1 }}</td>
                    <td>{{ item.field2 }}</td>
                    <td>{{ item.created_at }}</td>
                </tr>
                {% empty %}
                <tr>
                    <td colspan="4">No data available</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>

        <h1>Form 2</h1>
        <form method="post" class="form">
            {% csrf_token %}
            {{ form2.as_p }}
            {% if form2.errors %}
                <div class="error">
                    <p>Please correct the errors below:</p>
                    <ul>
                        {% for error in form2.errors %}
                        <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                </div>
            {% endif %}
            <button type="submit" class="btn">Submit Form 2</button>
        </form>

        <h2>Form 2 Data</h2>
        <table class="data-table">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Field 3</th>
                    <th>Field 4</th>
                    <th>Created At</th>
                </tr>
            </thead>
            <tbody>
                {% for item in form2_data %}
                <tr>
                    <td>{{ item.id }}</td>
                    <td>{{ item.field3 }}</td>
                    <td>{{ item.field4 }}</td>
                    <td>{{ item.created_at }}</td>
                </tr>
                {% empty %}
                <tr>
                    <td colspan="4">No data available</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
</body>
</html>
CSS
/* myapp/static/styles.css */
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    margin: 0;
    padding: 0;
}

.container {
    width: 80%;
    margin: 0 auto;
    padding: 20px;
    background: #ffffff;
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    margin-top: 50px;
}

h1 {
    color: #333;
    margin-bottom: 20px;
    border-bottom: 2px solid #007bff;
    padding-bottom: 10px;
}

.form {
    margin-bottom: 30px;
}

.btn {
    padding: 10px 20px;
    background-color: #007bff;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
}

.btn:hover {
    background-color: #0056b3;
}

input[type="text"], textarea {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
    font-size: 16px;
}
/* Existing styles */

.data-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 20px;
}

.data-table th, .data-table td {
    padding: 10px;
    border: 1px solid #ddd;
    text-align: left;
}

.data-table th {
    background-color: #f4f4f4;
}
body {
    font-family: Arial, sans-serif;
}

.container {
    width: 80%;
    margin: auto;
    padding: 20px;
}

.form {
    margin-bottom: 30px;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 20px;
}

.data-table th, .data-table td {
    border: 1px solid #ddd;
    padding: 8px;
    text-align: left;
}

.data-table th {
    background-color: #f2f2f2;
}

.btn {
    background-color: #4CAF50;
    color: white;
    border: none;
    padding: 10px 20px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    margin: 4px 2px;
    cursor: pointer;
}

.error {
    color: red;
    margin-top: 10px;
}

Define the static folder in the 'settings.py' file:

STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

5. Configure URLs:

If there is no "urls.py" file in "myapp" folder then create one to define the URLs of our view. Also connect our view to a URL pattern in 'myproject/urls.py'.

Python
# myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('handle-forms/', views.handle_forms, name='handle-forms'),
]

Add the following code in "myproject/urls.py":

Python
#myproject/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('myapp.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

6. Run the Server:

Make sure everything is correctly set up and then run your Django development server:

python manage.py runserver

Navigate to 'http://127.0.0.1:8000/handle-forms/' to see multiple forms in action with a more polished interface.

Expected Output:

file
fig: Form view

Filling Data in Form1:

new
fig: Filling data in form1

Output after submitting the form:

Screenshot-from-2024-09-19-15-47-57
fig: Output of Form1

Filling data in Form2:

Screenshot-from-2024-09-19-15-48-32
fig: filling data in form2

Output of Form2:

Screenshot-from-2024-09-19-15-50-55
fig: Output of Form2

Other way around would be to handle form submission using JavaScript. This would prevent page reloading when submitting the data.

Related articles:


    Next Article
    Article Tags :
    Practice Tags :

    Similar Reads