A Guide to the Django ModelForm - Creating Forms from Models

July 5, 2021, 2:47 p.m.
Django · 5 min read
A Guide to  the Django ModelForm - Creating Forms from Models
Last Modified: July 14, 2021, 11:50 a.m.

Django ModelForms is a helper class that allows you to create a Form class from an existing Django model. 

It honestly sounds more complicated than it actually is to implement. 

 

Create a Django Model

Add a model to models.py

mysite > main > models.py

from django.db import models

# Create your models here.

class Movie(models.Model):
	movie_title = models.CharField(max_length=150)
	release_year = models.IntegerField()
	director = models.CharField(max_length=100)
	movie_poster = models.ImageField(upload_to='images/', null=True)
	movie_plot = models.TextField()
	

	def __str__(self):
		return self.movie_title

The example above is from How to use Django Models. The model contains CharFields, IntegerField, ImageField, and a TextField. 

The function at the bottom returns the movie's title as the display name in the admin so it's easy to identify each model object. 

 

Configure the project for media uploads

mysite > mysite > settings.py

MEDIA_URL = '/media/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Add a URL for Django media file uploads in the settings if you have an ImageField or FileField in your models. 

 

mysite > mysite > urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf import settings #add this
from django.conf.urls.static import static #add this

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

if settings.DEBUG: #add this
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Also, add a URL path for the media files in the mysite > urls.py file. You'll notice these configurations are only for development.

Follow this guide to serve media files in production.

 

Install Pillow

Windows Command Prompt

(env) C:\Users\Owner\Desktop\Code\env\mysite> pip install Pillow

You'll also need to install Pillow for media upload support. If you want to know more about uploading files and Images in Django, checkout the Django File Uploads article. 

 

Run Migrations

Windows Command Prompt

(env) C:\Users\Owner\Desktop\Code\env\mysite> py manage.py makemigrations
(env) C:\Users\Owner\Desktop\Code\env\mysite> py manage.py migrate

You're also going to need to make migrations to create the Movie model and migrate to apply the migrations to the database.

 

Register the model in the Django admin.py

mysite > main > admin.py

from django.contrib import admin
from .models import Movie

# Register your models here.

admin.site.register(Movie)

The model is now added to the database, so register it in the admin.py file to view and update it in the Django administration panel.

Of course, you need a Django superuser account to access the admin page. Refer to How to use Django Models if you're new to the Django admin process. 

 

Create a Django ModelForm

Create a forms.py

mysite > main > (New File) forms.py

from django import forms

# Create your forms here.

Django does not come with a forms.py file so you need to make the file in the mysite > main directory, the same directory as the models.py file. 

Then you can import forms from Django at the top of the model. 

Now, rather than declaring Django form fields such as forms.CharField, let's import our existing Model.

Because if you haven't noticed already, the model fields are the same fields we want for the form. 

 

Create a ModelForm

mysite > main > forms.py

from django import forms
from .models import Movie 


# Create your forms here.

Please note, the official Django documentation does place ModelForms in the models.py file and imports ModelForm from django.forms. Instead, let's just add my ModelForms to the forms.py file. 

I personally prefer this method as I find it easier to refer to the forms.py file any time I'm looking for a form. 

 

mysite > main > forms.py

from django import forms
from .models import Movie 


# Create your forms here.
class MovieForm(forms.ModelForm):

    class Meta:
        model = Movie
        fields = ('movie_title', 'release_year', 'director', 'movie_poster', 'movie_plot')

Create your form class called MovieForm.  The Meta class is used to change the behavior of the ModelForm. Within it, specify the model your fields come from and the fields you want to use from that model. 

You can choose to add all of the fields or only a few. 

 

Create a Django Template for the form

Render the ModelForm and Model objects

mysite > mysite > views.py

from django.shortcuts import render, redirect
from .models import Movie
from .forms import MovieForm
from django.contrib import messages

# Create your views here.
def homepage(request):
	if request.method == "POST":
		movie_form = MovieForm(request.POST, request.FILES)
		if movie_form.is_valid():
			movie_form.save()
			messages.success(request, ('Your movie was successfully added!'))
		else:
			messages.error(request, 'Error saving form')
		
		
		return redirect("main:homepage")
	movie_form = MovieForm()
	movies = Movie.objects.all()
	return render(request=request, template_name="main/home.html", context={'movie_form':movie_form, 'movies':movies})

Head over to your views.py file and add an if condition for the form posting. Be sure to add request.FILES as the sources of the file data or your image will not save to the form.

If the form is valid, save the form. Then you can choose to show a Django Bootstrap message if the form is both valid or invalid.

Now, because the form is a MovieForm, saving the form will also add a new model object to the Movie model. This makes it easy for us to render the form and the model objects in the next step.

 

Render the ModelForm and Model objects

mysite > main > (New Folder) templates > (New Folder) main > (New File) home.html

<!DOCTYPE html>
<html>
  <head>
       <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Django ModelForms</title>
    </head>
    <body>

      {% load crispy_forms_tags %}  

        
        <div class="container">
          <!--Django Model Form-->
          <h2 class="my-4">Add a new movie</h2>
          <form method="post" enctype="multipart/form-data">
            {% csrf_token %}
                {{movie_form|crispy}}
                <button class="btn btn-primary my-4" type="submit">Submit</button>
          </form>
          <!--Django Model-->
          <h2 class="my-4">Movies</h2>
          <div class="row">
            {% for m in movies %}
            <div class="col-lg-4 col-md-6 col-sm-12 pb-4">
              <div class="card h-100 p-4">
                <img src="{{ m.movie_poster.url }}" class="card-img-top" alt="{{ m.movie_title}}">
                <h4>{{m.movie_title}}</h4>
                <p class="text-muted">{{m.release_year}} | {{m.director}}</p>
                <p>{{m.movie_plot}}</p>
              </div>
            </div>
            {% empty %}
            <p>No movies added.</p>
            {% endfor %}
          </div>
        </div>
    

    <!-- Option 1: Bootstrap Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
    </body>
</html>

Now let's create the Django template. This template will do two things: (1) render the MovieForm and (2)  render the Movie model objects as cards.

This template does use the Bootstrap 5.0.2 CDN.

If you are unfamiliar with rendering a Django form with Bootstrap, click here.

And if you are unfamiliar with rendering a Django model, click here.

You must add enctype="multipart/form-data", to <form>. This is to ensure uploaded files, such as ImageField and FileField, are encoded when submitted to the server.

I also want to point out that you can use the {% empty %} template tag to display text if the array is empty or not found. 

 

View in Browser

Django ModelForm

 

Django ModelForm output






Post a Comment
Join the community

0 Comments
1
Jaysha
Written By
Jaysha
Hello! I enjoy learning about new CSS frameworks, animation libraries, and SEO.