How to use Django Models

ยท13 min read

How to use Django Models

What is a Django model?

Django models are sources of information and behaviors stored within a single database table.

 

How does a Django model work?

Think of a Django model as a blueprint.

Each model is comprised of Django model fields that require user input.

Once the user completes the required fields, a model object is saved in the database.

The model's information is then accessible via a queryset, a callable collection of the model objects.

 

When do you use a Django model?

Use Django models when you need to dynamically load information in your project.

For example, if you create a blog don't hard code every piece of article content.

Create an article model with the article title, URL slug, and content as the model fields.

Then use the same template for each article by dynamically loading in the queryset based on the user request.

To learn more about this process visit, Django II, Lesson 4: Creating a blog

 

Are Django models required?

Django models are technically not required but are highly recommended.

It is good practice to use Django models whenever possible to minimize repetitive code but are ultimately not required for 

for unchanging or rarely changing site information.

 

Django model example

To demonstrate the purpose of Django models, let's create a Django models example that lists popular movies.

First, we will create the model and its fields, then we will log in to the Django administration site and create our model objects, and finally, we'll render the queryset using a for loop in the template. 

 


 

How to create a model in Django

env > mysite > main > models.py

from django.db import models

# Create your models here.

class Movie(models.Model):

Start by opening the Django models.py file in the app directory folder.

class Movie inherits (models.Model) just below the comment.

Next, we need to specify all of the information we want to list under each movie we add to our project.

 

Adding basic Django model fields

env > 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_plot = models.TextField()

First, add a field for the movie's title. This field is a Django models.CharField() or character field that takes in a maximum of 150 characters of text.

Next, add an IntegerField for the release year.

Let's also add a field for the director's name.

The last field we will add is for the movie's plot using Django models.Textfield(). This field allows paragraph text submissions.

 

How to change the Django model display name

env > 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_plot = models.TextField()
	

	def __str__(self):
		return self.movie_title

Before we move on, let's add a function that returns the movie's title as the display name.

If you forget to add this function it will list Movie object (1), Movie object (2), and so on in the Django admin, making it hard to know which object corresponds to a particular movie.

 

Make Django migrations to create the model in the database

macOS Terminal

(env)User-Macbook:mysite user$ python3 manage.py makemigrations
Migrations for 'main':
  main\migrations\0001_initial.py
    - Create model Movie


(env)User-Macbook:mysite user$

Windows Command Prompt

(env) C:\Users\Owner\Desktop\Code\env\mysite>py manage.py makemigrations
Migrations for 'main':
  main\migrations\0001_initial.py
    - Create model Movie

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

To use the model in the Django admin, we need to makemigrations and create the model that maps to a single database table. 

 

Migrate the model to the database

macOS Terminal

(env)User-Macbook:mysite user$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, main, sessions
Running migrations:
  Applying main.0001_initial... OK


(env)User-Macbook:mysite user$

Windows Command Prompt

(env) C:\Users\Owner\Desktop\Code\env\mysite>py manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, main, sessions
Running migrations:
  Applying main.0001_initial... OK

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

Now with the table created, we can migrate the model so all of the information uploaded to the model will be saved to the Django database, db.sqilte3

 

Register the model in the Django admin

env > mysite > main > admin.py

from django.contrib import admin
from .models import Movie

# Register your models here.

admin.site.register(Movie)

With the model successfully added to the database, we need to register it to the administration page so we can access it on the Django admin page.

Import Movie from the models.py file at the top of the page then add admin.site.register(Movie) below.

Save the file or the model will not appear on the admin page we will soon access.

 


 

Create an admin username and password

macOS Terminal

(env)User-Macbook:mysite user$ python3 manage.py createsuperuser
Username (leave blank to use 'owner'): admin
Email address:
Password: *****
Password (again): *****
Superuser created successfully.

(env)User-Macbook:mysite user$ python3 manage.py runserver

Windows Command Prompt

(env) C:\Users\Owner\Desktop\Code\env\mysite>py manage.py createsuperuser
Username (leave blank to use 'owner'): admin
Email address: 
Password: *****
Password (again): *****
Superuser created successfully.

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

Return to the CLI and run the command to createsuperuser in your project. Enter a username and password then press Enter to skip the optional email address field. Once the user is created, run the server again. This is the username and password needed to access the project's admin site so be sure to remember them.

 

Log in to the Django admin site

Go to http://127.0.0.1:8000/admin/ in a new tab and login to the Django administration page with the username and password just created. Upon login, you will see an interface with the model "Movies" listed below "Main", the name for your app.

Login in to Django Admin

 

Add a model object to the Django admin

Now let's add a movie to the model. Click on "Movies" then on the "Add movie" button in the top right corner. You will then be brought to a page that displays, yes you guessed it, the fields we added to the model in models.py. 

Add a movie to the Movie model

 


 

Render the model in the template

env > mysite > main > views.py

from django.shortcuts import render
from .models import Movie

# Create your views here.
def movies(request):
	movies = Movie.objects.all() #queryset containing all movies we just created
	return render(request=request, template_name="main/movies.html", context={'movies':movies})

It's time to render the model in a template. To do this, go to the view function of the template you want to render movies, in this case, it's movies.html, and add a queryset to the function. Then in the return render, set movies as the context returned when the template displays. 

 

Connect a path to the view

env > mysite > main > urls.py

from django.urls import path
from . import views

app_name = "main"   


urlpatterns = [
    path("", views.movies, name="movies"),
]

If you don't have a URL path that connects to the views.py function, make sure to add one to main > urls.py so the view renders in the browser. 

 

Add BootstrapCDN to the Django template

env > mysite > main > templates > main > movies.html

<!DOCTYPE html>
<html>
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Movies</title>
    <!--Bootstrap CSS-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  </head>
  <body>



    <!-- Optional Javascript -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  </body>
</html>

Next, go to the template specified in views.py so we can add the model to the template. 

We are using Bootstrap to help render the template but we will use Django Template Language (DTL) to render the model.

 

Add the Django model fields to the template

env > mysite > main > templates > main > movies.html

<!DOCTYPE html>
<html>
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Movies</title>
    <!--Bootstrap CSS-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  </head>
  <body>


    <div class="container p-4">
      <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">
            <h4>{{m.movie_title}}</h4>
            <p class="text-muted">{{m.release_year}} | {{m.director}}</p>
            <p>{{m.movie_plot}}</p>
          </div>
        </div>
        {% endfor %}
      </div>
    </div>


    <!-- Optional Javascript -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  </body>
</html>

Create a for loop written {% for m in movies %} with movies being the context we passed in the views function and m being the shorthand reference to movies within the loop.

Now, we can call on all of the fields we specified earlier in the models.py to render all of the information we added in the Django admin.

Add {{m.movie_title}}, {{m.release_year}}{{m.director}}, and {{m.movie_plot}} directly within the HTML elements, as if they were regular text.

After all of the fields are added, close the for loop with the tag {% endfor %}.

 

View the page in the browser

Once the model is added to the template, run the server and go to the URL that renders the template containing the model.

The Django model object you added to the admin should appear as if it were hardcoded in the template as a Bootstrap movie card.

First model

 


 

Add more model objects

Add as many movies as you'd like to the Django admin. Then when you reload the HTML template page in the browser, all of the new model objects will appear in the same format as the first. If you ever want to delete a model object, go to the admin, click on the object, and find the "Delete" button at the bottom of the edit page.

Multiple models

 


 

Django model field list

We just covered some of the basic Django model fields but there are many more fields easily implemented in models.py. For example:

  • use models.DateField() to add a publication date
  • use models.BooleanField() to add a checkbox
  • use models.SlugField() or models.URLField() to add a URL link
  • use models.DecimalField() to add numbers with decimal places

These are only some commonly used fields but there are several more model fields explained in the documentation.

 

Add an image upload field

env > 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/', None=True)
	movie_plot = models.TextField()
	

	def __str__(self):
		return self.movie_title

Django offers a field for uploading images to a model, it just requires a little more configuration to the project. First, add a new field to the model called ImageField that specifies the upload will go to a folder named 'images/'. We will also add None=True so the file is not required.

 

Configure settings.py

env > mysite > mysite > settings.py

...

MEDIA_URL = '/media/'

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

In settings.py, we need to specify a media uploads folder for the images upload to the movie_poster model field. The media folder will hold all of the images uploaded in the Django admin by a user instead of having to add the images directly to the project's static image folder.

 

Add the media folder to the URLs

env > 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)

Now in the mysite > urls.py add the code above to create a URL path to the media images uploaded to your project. This configuration is only for development, hence the if statement for debugging. In deployment, you will need to configure your static and media files for production.

 

Install Pillow

macOS Terminal

(env)User-Macbook:mysite user$ pip install Pillow

Windows Command Prompt

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

For the media upload to work correct, install Pillow in your activated virtual environment.

 

Make migrations again

macOS Terminal

(env)User-Macbook:mysite user$ python3 manage.py makemigrations
Migrations for 'main':
  main\migrations\0002_auto_20200601_1806.py
    - Add field movie_poster to movie

(env)User-Macbook:mysite user$ python3 manage.py migrate

Windows Command Prompt

(env) C:\Users\Owner\Desktop\code\env\mysite>py manage.py makemigrations
Migrations for 'main':
  main\migrations\0002_auto_20200601_1806.py
    - Add field movie_poster to movie

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

Because we added a new field to the model, we need to run migrations again to push the updates to the database. First, run makemigrations then run migrate. Run the server again once the migrations are made. 

 

Upload an image to a model

Log back into the admin site and click on one of the existing models. You will see a new field with a "Choose File" button. Click on the button and add the movie poster to the model object. Be sure to click "Save" or the update will not work.

Upload an image

 

Add the Django ImageField in the template

env > mysite > main > templates > main > movies.html

<!DOCTYPE html>
<html>
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Movies</title>
    <!--Bootstrap CSS-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  </head>
  <body>


    <div class="container p-4">
      <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>
        {% endfor %}
      </div>
    </div>


    <!-- Optional Javascript -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  </body>
</html>

Next, we need to add the image field to the template.

To do this you need an image HTML element with the src="{{ m.movie_poster.url }}" and an alt="{{m.title}}".

The class attribute is a custom Bootstrap class. Save the file.

 

View the images in the browser

When you refresh the browser tab again, the images you uploaded will display.

Images in browser

 

OPTIONAL: Resize the images

<!DOCTYPE html>
<html>
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Movies</title>
    <!--Bootstrap CSS-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  </head>
  <body>


    <div class="container p-4">
      <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}}" style="width: auto; height: 350px; object-fit: contain;">
            <br>
            <h4>{{m.movie_title}}</h4>
            <p class="text-muted">{{m.release_year}} | {{m.director}}</p>
            <p>{{m.movie_plot}}</p>
          </div>
        </div>
        {% endfor %}
      </div>
    </div>


    <!-- Optional Javascript -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  </body>
</html>

If you want all of the cards and images to display at the same height add the following style attributes to the image element: style="width: auto; height: 350px; object-fit: contain;".These attributes work together to specify the image height while scaling down the image to fit with its parent element.

When you reload the page, the images will appear at the same height.

Scaled down images