Django Forms

Filed Under: Django

In this tutorial, we’ll be discussing Forms in our Django Project. In the previous tutorials, we had discussed Django Templates and Django Models. Today, we’ll see how Django Forms work and use them with Templates as well.

Django Forms

Forms are an essential part of any web application that requires user input. Be it login forms, entering survey details, writing blog posts and comments(like we do on JournalDev!).

Django Forms basically does three simple things:

  • Read user input
  • Validate it.
  • Convert it into Python data types/objects
Forms vs Models

Models map fields into types for the database. Forms map fields into Python types.

Let’s first discuss HTML forms since those are what would be finally displayed on the screen.

HTML Forms

To create a form in HTML, enclose it in the <form> ... <form/> tags


<form action="/goto_url/" method="post">
    <label for="name">Enter name: </label>
    <input id="name" type="text" name="name_field" value=".">
    <input type="submit" value="OK">

The form tag consists of an action which takes you to the mentioned url path when submit input type is clicked.

In the method, we set it to GET or POST normally. The label acts as a hint for the id of the input tag it is linked to.

Note: There are several other fields such as DateField, BooleanField and many more that can be used inside forms.


GET is used to send the data in the form of a string which gets appended to the URL. This doesn’t change anything in the database.

POST method is used to bundle up the data and send it to the server. It gets a response back. This is normally used to update the database.

GET is vulnerable to cross forgery site attacks since the data is available in the url itself.

GET shouldn’t be used in cases such as password forms. A POST is more resistant to attacks.

Django Form class

Django makes our lives easier by handling the tiny details such as creating and re-creating the forms in the HTML page, validating the data entered and performing any actions set upon the forms.

Just like HTML has the form tag, Django has a Form class.
The Form class is defined as:

from django import forms

class FirstForm(forms.Form):
    name = forms.CharField(label='Your name', max_length=100)

We can render this class using Django Templates in the HTML page.
When the Submit button is clicked, the Form class would do the validation check using the is_valid() method on the instance of the above class.

Once the validation is cleared the form data is available in the Form class’s cleaned_data attribute.

Django Forms can be of two types:

unbound – No data is present in the forms. They are empty.

bound – Data is filled in these types of forms.

The above concepts may be difficult to digest. The best possible way is to learn by example.

In the next section, we’ll create a basic Django Web Application with Forms implemented.

Our application would take responses and show it on the next screen.

Quick Setup

Let’s create a new Django Project and start a new app inside it named responseapp.

Following is the ordered list of commands we’d entered in the terminal. To know the details visit our First Django Tutorial.

mkdir DjangoForms
cd DjangoForms
virtualenv -p /usr/local/bin/python3 env
source env/bin/activate
pip3 install django
django-admin startproject DjangoFormsBasics
cd DjangoFormsBasics
python3 runserver
django-admin startapp responseapp
cd responseapp
mkdir templates
cd templates
touch responseform.html
touch thankyou.html

Inside the responseapp, we’ve created a templates folder which will hold the html files.
Inside the templates folder, add two html files for the two paged web application we’ll build next.

Create two new python files: and

cd ..

Project Structure

django forms project structure

Don’t forget to add the Django app in the file:

django forms setting py


Add the following code in your file:

from django import forms

class MyForm(forms.Form):
 name = forms.CharField(label='Enter your name', max_length=100)
 email = forms.EmailField(label='Enter your email', max_length=100)
 feedback = forms.CharField(widget=forms.Textarea(attrs={'width':"100%", 'cols' : "80", 'rows': "20", }))

We’ve added three fields: CharFields, EmailFields, and a CharField with TextArea width and height specified.

The code for file is given below:

from django.shortcuts import render
from responseapp.forms import MyForm

def responseform(request):
     form = MyForm()

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

You must use csrf(Cross Site Request Forgeries) for Django Forms which have the method POST.

This renders the Django Form and uses the template language by passing the complete form instance to the HTML.

The code for our initial responseform.html class is given below:

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title>Django Forms Tutorial</title>
<h2>Django Forms Tutorial</h2>

    {% csrf_token %}
<input type="submit" value="Submit" />

Run the following commands on your terminal on the inner DjangoFormBasics folder:

python3 migrate
python3 runserver

Note: You must specify the url patterns. Check out the files defined later in this tutorial.

Following is the output of the application in action.

django forms first output

WHOOPS! It looks ugly horizontally. We can arrange the Forms in the following orders:

  • form.as_ul: Display fields as unordered list
  • form.as_p: Display fields as paragraph in separate line
  • form.as_table: Display fields as table elements



For form_as_ul you must enclose it in the ul tag.

Also, the submit button doesn’t work, let’s add another html page which will catch the form responses and display there.

The updated code for the responseform.html is given below:

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title>Django Forms Tutorial</title>
<h2>Django Forms Tutorial</h2>

<form action="/thankyou/" method="post">
    {% csrf_token %}

<input type="submit" value="Submit" />

In the above code, we’ve added a method and action. When submit is clicked the user would be taken to the /thankyou/ page with the form data POSTed.

The code for the file is given below:

from django.shortcuts import render
from responseapp.forms import MyForm
from django.template import loader
from django.http import HttpResponse

def responseform(request):
 #if form is submitted
     if request.method == 'POST':
        myForm = MyForm(request.POST)

        if myForm.is_valid():
            name = myForm.cleaned_data['name']
            email = myForm.cleaned_data['email']
            feedback = myForm.cleaned_data['feedback']

            context = {
            'name': name,
            'email': email,
            'feedback': feedback

            template = loader.get_template('thankyou.html')

            return HttpResponse(template.render(context, request))

         form = MyForm()

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

Initially, the else statement will execute and create an empty form.

Later when submit is clicked, if block is executed and if the form is validated we load the thankyou.html page using Loaders with Django Templates.

The form data is passed to the thankyou.html class as:

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title>Thank You</title>
<h2>Response Entered by you:</h2>
<form method="post">

            <li>Name: <strong>{{ name }}</strong></li>

            <li>Email: <strong>{{ email }}</strong></li>

            <li>Feedback: <strong>{{ feedback }}</strong></li>

The code for the created inside the responseapp folder is:

from django.urls import path
from django.contrib import admin

from responseapp import views as responseapp_views

urlpatterns = [
 path('response/', responseapp_views.responseform),
 path('thankyou/', responseapp_views.responseform),


responseapp_views is same as responseapp.views. It calls the file from where the application starts.

The below file must be included in the outer file defined in the DjangoForm project:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('', include('responseapp.urls'))

The output of the application in action is:

django form final output

This brings an end to this tutorial. You can download the project from below:


  1. manoj says:

    after some debugging this program form works fine thanks

  2. Nisha says:

    please help me with my following error.

    Request Method: POST
    Request URL: http://localhost:7000/response/thankyou/
    Django Version: 3.1.5
    Exception Type: TypeError
    Exception Value:
    list indices must be integers or slices, not str

    the error is in the following line>>>

    if form.is_valid():
    name = form.changed_data[‘name’]
    email = form.changed_data[’email’]
    feedback = form.changed_data[‘feedback’]

  3. Taimur says:

    Blog was helpful. Thanks

  4. Md Bakhtiar Chowdhury says:

    i have same problem

  5. judit says:

    it does not work
    python3 migrate
    module ‘django.contrib’ has no attribute ‘staticfilesresponseapp’

  6. Raakesh says:

    Thanks for the awesome article, you just made my day. I need one help with the form save in sql.

    How do I do that? Please help me how to save the form and view in separate template

Comments are closed.

Generic selectors
Exact matches only
Search in title
Search in content