Django ModelForms

Filed Under: Django

In this tutorial, we’ll be discussing and implementing ModelForms in our Django Web Application. Do brush up Django Models and Django Forms before proceeding ahead.

Django ModelForms

Instead of creating individual fields redundantly for Django Forms we can map them to a particular Model. This is called ModelForms.

ModelForm is a class that can be imported using:


from django.forms import ModelForm

Following are the benefits of using ModelForms:

  • A ModelForm is useful when we want to create forms from Database fields.
  • We can add our own validation checkers on the Database Model fields.
  • We can include and exclude fields from the Model as per our choice.
  • Easy to quickly save Form data to the database.
ModelForm vs Form
ModelForm gets their field definitions from a specified model class. It also has helper methods to save the forms to the database. These features are not present in Forms.

save()
save method is called on the Django ModelForm instance in order to save the data to the database (SQLite3).

Calling save would run the validation check. A ValueError will be raised if the data in the form doesn’t validate.

save() method also accepts an optional argument commit. Setting commit to false would not save the data to the database.

Creating ModelForm Class

To create a ModelForm class, we need to add a class Meta inside it. Inside the Meta class, we instantiate the Django Model class.

We must include/exclude the fields we want to use in our Model. To include fields we set them in a Python Array.

If you want to include all fields set fields = '__all__'.

To exclude fields set them inside the respective array.

An example of our Model class and ModelForm class is given below:


from django.db import models
from django.forms import ModelForm

class SampleModel(models.Model):

    title = models.CharField(max_length=100)
    description = models.CharField(max_length=255)

    def __str__(self):
        return self.title

class SampleModelForm(ModelForm):
    class Meta:
        model = SampleModel
        fields = ['title']

In the above code, our SampleModelForm omits the field description.
Displaying the ModelForm in our Django Web application is quite similar to the way we did in the Django Forms tutorial.

To save the ModelForm to the database we do:


data = SampleModel(title='Me')
form = SampleModelForm(request.POST, instance=data)
form.save()

save(commit=False) is generally used when we want to keep an altered version of the data with us without saving. Typically for testing purposes.

For that we can do:


form = SampleModelForm(request.POST)
model = form.save(commit=False)
model.title = 'Anupam testing'
model.save()
In order to use commit False we must include the following import statement.

from django.forms import modelformset_factory

In the following section, we’ll build a simple Django ModelForms web application.

Project Structure

django model form

Note: display0.html contains a backup of display.html.

To set up the above project, run the following set of commands one after the other in your terminal.


mkdir DjangoModelForm
cd DjangoModelForm
virtualenv -p /usr/local/bin/python3 env
source env/bin/activate
pip3 install django
django-admin startproject ModelFormProject
cd ModelFormProject
python3 manage.py runserver
django-admin startapp detailsapp
cd detailsapp
mkdir templates
cd templates
touch userdetails.html
touch display.html
cd ..
touch urls.py
touch forms.py

Our Django app’s name is detailsapp. Add it in the settings.py INSTALLED_APPS list.
userdetails.html is the first page of our application.

Code

The code for the urls.py file inside the detailsapp folder is:


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

from detailsapp import views as detailsapp_views

urlpatterns = [
 path('userdetails/', detailsapp_views.userDetails),
 path('display/', detailsapp_views.userDetails),

path('', admin.site.urls),
]


The code for the urls.py file inside the ModelFormProject folder is:


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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('detailsapp.urls'))
]


models.py


from django.db import models
class UserDetails(models.Model):

    title = models.CharField(max_length=100)
    gender = models.CharField(max_length=255)
    notes = models.CharField(max_length=255)

    def __str__(self):
        return self.title


forms.py


from django.forms import ModelForm
from detailsapp.models import UserDetails

class UserModelForm(ModelForm):
    class Meta:
        model = UserDetails
        fields = ['title', 'notes']


views.py


from django.shortcuts import render
from django.db import models
from detailsapp.models import UserDetails
from django.template import loader
from django.http import HttpResponse
from django.forms import modelformset_factory

# Create your views here.

from .forms import UserModelForm

def userDetails(request):

    if request.method == 'POST':
        form = UserModelForm(request.POST)
        if form.is_valid():

            u = form.save()
            users = UserDetails.objects.all()

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

            

    else:
        form_class = UserModelForm

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

When the form is empty the else statement is executed and is used to create the form in the userdetails.html file:


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

<form action="/display/" method="post">
    {% csrf_token %}
    <table>
    {{form.as_table}}

 </table>
<input type="submit" value="Submit" />
</form>
</body>
</html>

users = UserDetails.objects.all() is used to retrieve all the entries from the database and pass it to the display.html file:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ModelForm Tutorial</title>
</head>
<body>
<h2>All User Details</h2>
<table>
    {% for item in users %}
    <tr>
        <td><b>Title:</b>{{ item.title }}</td>
        <td><b>Gender:</b> {{ item.gender|default:"NA" }}</td>
        <td><b>Notes:</b> {{ item.notes }}</td>
    </tr>
    <tr>
    <td colspan="2" class="divider"><hr/></td>
</tr>
    {% endfor %}
</table>
</body>
</html>

Since the gender field is excluded, we’ve set a default value on it using Django Templates.

To run the application on your localhost we must form save the Models in the database


python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py runserver

The output of the application in action is given below:

django modelform output 1

In order to clear the database, run the following command:


python3 manage.py flush

This brings an end to this tutorial. We’ll be covering more custom helper functions and adding our own validation checks in the next tutorial.
In the source code below we’ve added the piece of code to use save(commit=False). Uncomment it and comment out the code that uses save(). We’ve added the template for it in display0.html. Copy it to display.html.

Comments

  1. omar ahmed says:

    good tutorial
    thank you

Leave a Reply

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

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages