Jun 01, 2020
DjangoBootstrap ยท13 min read
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.
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.
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.
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.
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:
models.DateField()
to add a publication datemodels.BooleanField()
to add a checkboxmodels.SlugField()
or models.URLField()
to add a URL linkmodels.DecimalField()
to add numbers with decimal placesThese 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.
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.
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.
Follow us@ordinarycoders