Django Forms and ModelForms

Django Forms and ModelForms

·

12 min read

Introduction

Most Django websites you build will have some form of user input (collecting data from users) - and that's where forms come in. Forms are an integral part of the Django framework. In this article we will look at the following:

  • Forms
  • ModelForms

Before we begin, this article assumes you know how to setup a Django project.

Go ahead and create an app with the python manage.py startapp <app_name> command. You can name the app anything you want.

In your Django app, create a forms.py file. This file is where we are going to build our forms.

Forms

Django has a Form class that allows us to create forms. The role of this class is mainly to automate the process of manually having to write HTML elements - as much as possible. Imagine if we had to write every HTML tag just to be able to render a form with so many input fields? It would be tedious. That's where Django Forms come in and make our life easier. All we have to do is just create a subclass of the Form class and specify the fields we want. We are going to call the class ApplicantForm. That's all we have to do and Django will work its "magic" and produce a form for us. How cool is that?

When you specify a Form field, Django maps that field to an HTML input tag that corresponds with it. For example: a CharField field is mapped to an <input type="text"> element.

To demonstrate this, let's build a simple form that asks an applicant for their first and last name.

In your forms.py file enter the following code:

from django import forms

class ApplicantForm(forms.Form):
    first_name = forms.CharField(max_length=100)
    last_name = forms.CharField(max_length=100)

In the code above, we imported forms from Django, to allow our ApplicantForm class to inherit from the Form class. We then specified 2 fields - all of type: Charfield. We also specified max_length=100 - to tell Django that we want this input field in the HTML to have maxlength=100.

Now we have created a form, and it's ready for use.

Before we can show this form on our website, we'll first have to process it in a view and specify a URL path for it. Let's do that now.

In the views.py file, add the following code:

from django.shortcuts import render
from django.views.generic.edit import FormView
from . forms import ApplicantForm

####-  Function-based View -####

def index(request):
    if request.method=='POST':
        form = ApplicantForm(request.POST)
        if form.is_valid():
            pass

    else:
        form = ApplicantForm()

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


####-Class-based View -####

class ApplicantView(FormView):
    template_name = 'form.html'
    form_class = ApplicantForm
    success_url = '/'

In the code above we created a view to process our form and render it to the specified template - form.html. We have 2 views which do exactly the same thing. In case you are wondering why that is? It's because Django gives us the flexibility of either using functions or classes to write our views. And as such, people sometimes prefer one over the other - which is why we have both of them, so you can choose the one you prefer.

Function-based View

In the function-based view, we first ask if the form is being submitted - with if request.method=='POST': If it is, we'll create a variable named form to hold an instance of our ArticleForm and populate it with the data returned in the request - and check if the form is valid, with if form.is_valid(). The is_valid() method returns a boolean - and if the form has no errors, it returns True. We can then access the validated data in the cleaned_data attribute for further processing, but that is beyond the scope of this article.

If we are not submitting the form (when it's a GET request), we'll just instantiate an empty ArticleForm saved in "form" and render that instead. This happens when we first request the page, we get an empty form to fill out.

And finally, we render the form in the specified HTML template - form.html. We can access the form object from our template using the "form" name we specified in the dictionary {'form': form}.

Class-based View

The class-based view is very straightforward and requires very minimal code to render the form. This is because our view inherits from FormView, which handles all the logic for us, so we just have to specify the name of the template where we want to render the form on, the form class to be rendered (in this case ApplicantForm), and a success URL for redirecting us to a specific page when we successfully submit the form. This is one of the main advantages of using class-based views - it allows us to write very little code.

Now, all we have to do is just render the form on the template specified, and a url path to our view. That's it.

ModelForm

In the previous section, we created forms and rendered them on our website. That was one way to use forms in Django. However, when we want to save the information we collected from our users, we have to use a database for that. In this section, we will see how to create forms from our database models and save the information in the database as well.

Most of the time we have models in our application that get populated with information we collect from our users, through forms. That's what we are going to demonstrate here. We are going to create a model with a few fields.

In your models.py file, add the following code:

from django.db import models

# Create your models here.

class Applicant(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    nickname = models.CharField(max_length=100)

    def __str__(self):
        return self.first_name

We will use the Applicant class in the code above as our model.

Previously, we had to specify every field in our ApplicantForm to tell Django that we want those fields in our form. Here, we will make use of the Django ModelForm class to tell Django to build our form from the model we specified. This saves us a lot of time from having to specify every field on both our model and form. Django will use the model specified to map the fields we want to form fields.

In your forms.py file, add the following block of code:

from django import forms
from . models import Applicant

class ApplicantModelForm(forms.ModelForm):
    class Meta:
        model = Applicant
        fields = '__all__'

In the code above, our ApplicantModelForm inherits from ModelForm. We used a Meta class to specify the model we want and the fields of the model we want to be included in our forms - in this case, "__all__" - to tell Django that we want all the fields in our Applicant model to be on our form.

In most cases, you will give a list of the fields you want to be included in the form because there are some fields you do not want the user to be able to access or change. If we had a student ID field in our Applicant model, we wouldn't have included it in our form because you don't want a student to be able to change their student ID. So, in that case, we would do something like:

fields = ['first_name', 'last_name']

Then when Django builds the form, it will omit the student_id field from the form and only use the ones specified in fields.

And just like that, we have created a form from our model - without much code.

The views are almost the same as the ones we implemented above:

from django.urls import reverse_lazy
from django.views.generic.edit import CreateView

def modelform_view(request):
    if request.method=='POST':
        form = ApplicantModelForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('/default')

    else:
        form = ApplicantForm()

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



class ApplicantModelCreateView):
    template_name = 'form.html'
    form_class = ApplicantModelForm
    success_url = reverse_lazy('forms:default')

The difference in the views here is that we have used CreateView instead of FormView, as we have seen in the previous section. This is because CreateView is more suitable for forms that save data to the database.

And that is one of the ways you can create forms in Django. We can do more advanced stuff like processing the form and accessing and editing the data before saving it to the database but that's beyond the scope of this introductory article. If you would like to see how to do that, just let me know in the comments.

Summary

To summarize, we have:

  • Shown how to create forms and render them on our website.
  • Seen the difference between regular Forms and ModelForms, and when to use each.
  • Seen--in part--how to handle forms in views - with functions and classes.