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 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()
from django.forms import modelformset_factory
In the following section, we’ll build a simple Django ModelForms web application.
Project Structure
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:
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.
thank you , it worked for me
I would like to see a modification of this post to should how to handle this form with two ( or more) buttons, e.g. submit, cancel. I would like to see how this would be handled in the .html, the views.py and the URLs.py files. In the submit case, the form data would be processed. In the cancel case, a redirect to another page would occur.
Thanks for any help.
good tutorial
thank you