An introduction to Django Forms

Django Forms

Django Forms are a way to accept user input as text, images, or files from the web frontend.

The straightforward example of forms that we came across was the Django admin site’s login page. Admin site took input text “username” and an input text “password” from us. 

There are two ways to use forms on our website;

  1. One using the <form> attribute in HTML Template files
  2. Using the Django Forms Model class.

We will learn just the basics of HTML forms to know what they are. Our primary focus will be Django forms itself.

Creating HTML forms for Django

We can create forms in HTML itself using the <form> attribute and get information from client using <input> attribute. The syntax for a typical HTML form is given below:

<form action="</action/>" method="post">
    <label for="element_id">Your name: </label>
    <input id="element_id" type="text" name="<name>" value="<pre-set_value>">
    <input type="submit" value="OK">
</form>

Let’s understand what the above code means:

  1. Action: This tells HTML where to send the submitted form data. It usually contains the URL we want to send the data to
  2. Method=”POST” This is a particular Method that we use while sending information to the server. There is a GET method as well, which we will need in this article.
  3. label for: This label gives a name to identify that particular label. For eg: <label for =’fname’>First Name:</label> Here we are giving a short name fname to identify the label “First Name.”
  4. <input id=, type=, name=, value= >: This input attribute is the most important in the HTML form, Input specifies the form field that we will take from the client—for example, the type, name, pre-set value assigned to it, etc.
  5. <input type=” submit”: This input submits the Form client entered.

Instead of using the <input> attribute to create form fields, we can use Django forms, which is a much efficient way. But before that, we need to learn more about GET and POST methods.

When to use GET and when to use POST

By default, the browser uses the GET method to request resources from the server.

For example, continuing from our books model example, we automatically use GET requests in the backend to pull the books’ data. Since we aren’t modifying the list on the front-end, this method works perfectly fine.

But let’s say if we want to add a book into the model DB. Then we are basically changing the DB elements, and hence then we require the POST method. Therefore, the POST method sends some information to the server. 

When we changed the information regarding a Book or were adding a Book in the Django admin site, we used the POST method.

And when we were just looking at the list of books under BookModel in the admin site, we used the GET method.

There are other HTTP methods apart from this as well, which will learn in the REST API framework article.

Leveraging Django Forms

The working of Django forms is similar to that of Django Models. We create a form class and save them in a separate forms.py file.

The only difference between models and forms is that in models, we map model fields to the database fields while in forms, we map the form fields to the HTML form <input> elements.

Another interesting fact about forms is that we display blank forms on the website and take information from the client to store it, while with models, we show the stored data from the database to the client. 

Creating forms.py python file inside the Django app.

Inside the Django app, create a new python file and name it forms.py

Forms .py
Forms.py

Creating a SearchForm to search for Book from the Book_website

We will now create a simple form that will take the name of the book as input and then redirect us to that book’s website. Hence let’s get started.

1. Creating a SearchForm in forms.py

Inside forms.py first we need to import forms library.

from django.forms import forms

After that, include the following code to create a SearchForm with a book_title field.

class SearchForm(forms.Form):
    book_title = forms.CharField(label = "book_title",max_length =80)

The syntax is similar to that of a model including max_length.

The label here has the same function as that of the label we learned in HTML forms.

2. Creating a SearchBookView in views.py 

In views.py, create a function View with the name SearchBookView.

Now there can be two ways possible:

  1. The client reaches the webpage using a GET method.
  • This will happen when the client opens the webpage for the first time, or else wants to search for another book.
  1. The client reaches the webpage using a POST method.
  • This will happen when the client enters the book name and then presses the submit/search button.

Therefore the View will have to tackle both these situations.

1. Code for the GET method

When the client uses the GET method, he must get a blank form to enter the book name.

Thus, in this case, Our code will simply have the code.

form = SearchForm()

Just like models, we create a new form object and will pass it on to the HTML file.

2. Code for the POST method

When the client uses the POST method, he will be redirected to the Book webpage that we created in our previous articles(books/<book_name>)

Therefore, the code to perform this task will be:

if request.method == 'POST':
        form = SearchForm(request.POST)

        if form.is_valid():
            book_title = form.cleaned_data['book_title']

            try:
                book = BookModel.objects.get(title = book_title)
            except book_title.DoesNotExist():
                raise Http404('This book does not exist')

            return HttpResponseRedirect(f'/books/{book_title}', {'book':book})

Here

  • form = SearchForm(request.POST) saves the information that the client entered into the created form object “form.
  • form.is_valid() checks if the information entered in the field is valid or not. i.e., e.g., whether we have entered email only in the EmailField or not.
  • form.cleaned_data[‘book_title’]: This attribute of the form library automatically converts the information entered by the client into the correct python accepted format, and thus the name cleaned_data
  • try and except block: This is called exceptional handling in python which you might have learned in Python Exceptional Handling
  • If the Book Title that the client entered is present in the DB, then we will get the information about the book using
 book = BookModel.objects.get(title = book_title)
  • Otherwise, if the book does not exist, then we raise a Http404 error, which is present in the Django.shortcuts library
  • And once we save the information about the book from the DB, we use
HttpResponseRedirect("<url>",<context>)

This attribute redirects the client to the URL mentioned, along with the context dictionary.

Now that we have looked into the two parts of the SearchBookView, let’s combine them to get the complete final SearchBookview

from django.shortcuts import render,HttpResponse,HttpResponseRedirect,Http404

from .models import BookModel
from .forms import SearchForm
def SearchBookView(request):

    if request.method == 'POST':
        form = SearchForm(request.POST)

        if form.is_valid():
            book_title = form.cleaned_data['book_title']

            try:
                book = BookModel.objects.get(title = book_title)
            except book_title.DoesNotExist():
                raise Http404('This book does not exist')

            return HttpResponseRedirect(f'/books/{book_title}', {'book':book})
        
    else:
        form = SearchForm()
        context ={
            'form':form,
        }
    return render(request, 'books_website/SearchBook.html', context)

Therefore, if the request is POST, we are redirecting the user to /books/<book_title> URL or else if the client is using GET, we are simply showing him a blank form.

SearchBookView
SearchBookView

Don’t forget to import HttpResponseRedirect, Http404 from django.shortcuts and searchForm from forms.py

3. Creating the SearchBook.html template file in the templates folder

Since we have created a Django form, we do not have to create Input fields again for the book_title.

We just have to add the submit button in the form, and that’s it.

So let’s just create the HTML file.

<form method ='post'>
    {% csrf_token %}
    {{form}}
    <input type="submit" value = "Submit">
</form>

{% csrf_token %} that is the Cross-Site Request Forgery tokens protects against csrf attacks and hence used for security purposes for the forms.

SearchBook HTML
SearchBook HTML

4. Creating a URL endpoint for the SearchBookView in urls.py 

Now, we will create a new URL path (book/search) for the SearchBookView we created.

We have learned in Django URL mapping, how to map a View to the URL, so let us do that here again.

path('book/search', SearchBookView, name='SearchBookView'),
URL
URL

That’s it, Now lets run the server

python manage.py runserver
Browser
Browser

Search for Ghostbuster, and hit Submit

Ghostbuster
Ghostbuster

Now, if you see, most of the webpages have their search buttons on the books web page(books/) itself. To do that, we need to combine the SearchBookView and BookView.

So just cut the code from SearchBookView and paste it in BookView. Then the BookView will look like this:

def BookView(request):
    books = BookModel.objects.all()
 
    if request.method == 'POST':
        form = SearchForm(request.POST)

        if form.is_valid():
            book_title = form.cleaned_data['book_title']

            try:
                book = BookModel.objects.get(title = book_title)
            except book_title.DoesNotExist():
                raise Http404('This book does not exist')

            return HttpResponseRedirect(f'/books/{book_title}', {'book':book})
        
    else:
        form = SearchForm()
        context ={
            'books':books,
            'form':form,
        }
    return render(request,'books_website/BookView.html', context)

Try to understand the code above and see how I have modified the searchBookView to include it in here.

Now here, since we have the search form in the web page below itself, we will include the SearchBook.html inside our BookView.html.

Now as SearchBook.html is a part of BookView.html, we can just render the BookView.html template itself (at the bottom) and remove the line

render(request, 'books_website/SearchBook.html',context)
BookView
BookView

That’s it; now we don’t even require the endpoint we just created. So delete the URL path (book/search).

Load up server and open browser

Books
Books
Book Ghostbuster
Book Ghostbuster

Hit submit and check

Ghostbuster
Ghostbuster

Creating Forms using ModelForm

If we want to save the form data into a DB table, then we need to create a Django model for that.

Django provides a way to link the information entered by the client through the form to the Model created to save the data.

Using ModelForm, we can efficiently perform the above task without writing much code. So let’s begin

Creating a Book-review form

We will create a review form on the book (books/<book_name>) webpage so that viewers can comment about the book.

1. Creating BookReviewModel in models.py

In models.py, create a new model BookReviewModel and write the required model fields as shown in the code below.

class BookReviewModel(models.Model):

    name = models.CharField(max_length = 80)
    review = models.TextField()

    class Meta:
        ordering = ['name']
    
    def __str__(self):
        return f"comment by {self.name}"

Here, we are using Textfield, since the reviews can be long enough. This model is easy to understand since we learned this in Django Models article

2. Creating a Model form in forms.py

Now in the forms.py, create a form as shown.

class ReviewForm(forms.ModelForm):
    class Meta:
        model = BookReviewModel
        fields =('name','review',)

Here:

  • Import BookReviewModel from .models
from .models import BookReviewModel
  • Then we use Meta Class (which we learned about in Django Models) to include our Django Model and also to mention the fields that we want in the form
ReviewForm
ReviewForm

3. Creating BookReviewView in views.py

We will write a function view similar to the one we wrote while making a Search Form.

In Views.py, create a new function view BookReviewView and add the following code.

def BookReviewView(request):

    if request.method == 'POST':
        form = ReviewForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponse('Your review has been taken')

    else:
        form = ReviewForm()
        context = {
            'form':form,
        }
    return render(request, 'books_website/ReviewBook.html', context)

Here:

  • If form is valid, then we are simply using the save attribute to store the information entered by client into the DB.

See how simple it is to save a Form entry into the DB. we will now create the ReviewBook.html template file.

BookReviewView
BookReviewView

4. Creating ReviewBook.html template file.

In the templates/books_website, create a new file with the name ReviewBook.html

Just as we did above,we will create a form attribute.

<form method='post'>
    {% csrf_token %}
    {{form}}
    <input type="submit" value = "submit">
</form>

That’s it, our HTML file is ready

5. Creating the URL path to the BookReviewView

Now we just have to create a new path to the BookReviewView.

Go to urls.py and just add

path('book/review', BookReviewView, name='BookReviewView'),

Also don’t forget to register the BookReview Model in the admins.py

admin.site.register(BookReviewModel)

That’s it guys!! Lets run the server and go to (book/review) webpage.

Browser
Browser
Browser
Browser

And then press the submit button, you will see the Thank you for your response webpage.

Browser 6
Browser 6

Now if you go to the admin site, and check inside the BookReviewModel, you will see that the form entry is saved.

Admin Site
Admin Site

Conclusion

That’s all for the Django forms tutorial! We hope you have gained all the basics of Django forms and how they are linked with HTML forms. Also, you can learn more about the Django forms from the official documentation.

Stay tuned for more advanced tutorials on Django topics!