Understand Representing an Entity With a Model
Whatever your web application does, it will likely need to store some data.
Programmers often begin by identifying the different entities about which they need to store data. For example, we want to track different bands and listings of merch for sale in our application. So there are two entities right there: bands and listings.
For each entity you want to store data about, you create a model to represent that entity. Let’s start with a Band model.
A model defines the characteristics that you want to store about a particular entity.
So the Band model could have as its characteristics a title, a genre, and the year it became active. These are also known as fields.
You can then use the model to create individual objects, or instances, of that model that each have their own unique characteristics.
Wait a minute… aren't you describing a class?
You’d be forgiven for thinking that model is just another name for class! And you would be half correct - you create a model in Django by defining a Python class.
So what makes a model different from a regular class?
Typically in MVC and MVT frameworks, a model can also store (or persist) its data to a database for later use. This is in contrast to regular classes and objects, whose data exists temporarily - perhaps only while the application is running.
Also, the characteristics of Python classes are called attributes, but when a model saves an attribute to the database, it’s called a field.
Ok, do I need to know how to write code that interacts with a database to make a model?
Actually, no. This is one of the advantages of using a framework like Django - all of the functionality for persisting data to a database has already been written for you. All you have to do is make your model inherit from Django’s models.Model
class. Your model then inherits all the methods (behaviors) required to do things like select data from, and insert data into, a database.
You won’t have to write code that interacts with a database, but you will be learning how to interact with Django’s models to do the same thing. (Don’t panic - it’s easier! 😉 )
Let’s create the first model now. We’ll keep things simple, to begin with - this model will represent a band, but we’re only going to define one characteristic for now: the band’s name.
Add a Model to Models.py
Open up models.py, which looks like this:
# listings/models.py
from django.db import models
# Create your models here.
Again, Django has left a helpful comment. Now that you know where the models go, let’s replace that comment with the following code:
# listings/models.py
class Band(models.Model):
name = models.fields.CharField(max_length=100)
We’ve defined the class, named it Band
, and made it inherit from models.Model, which is Django’s model base class.
Then add a class attribute to the class: name
. To this attribute, assign a CharField
- which is short for character field. This field will store character/text/string data, which would be the appropriate data type for a name.
Also set the maximum length of a Band
’s name at 100.
And there’s the first model.
As with Python classes, you can use Django models to create instances of that class, e.g., band = Band()
.
So can we start creating Band objects now?
Not just yet.
As we’ve said, one feature of a model is that it can store its data in a database. We created our database in the setup chapter, but it doesn’t know anything about our Band model. And that’s where migrations come in.
Understand Managing Database State With a Migration
If we want to store Bands in our database, we’ll need a new table containing a column for each field that we’ve added to our Band model and an id column to act as the primary key - a unique identifier for each row in the table.
In terms of its tables and their columns, the structure of a database is called a schema.
If we were building the database schema manually, we might write an SQL query or use a database management GUI to create the first table.
But in Django, you do things differently. First, you use a subcommand from the command-line utility that will generate instructions for building the table. And then, use another subcommand to execute those instructions. These instructions are called a migration.
A migration is a set of instructions for moving your database schema from one state to another. Importantly, these instructions can be executed automatically as code.
But why shouldn’t we create the table manually?
In programming, we often talk about “configuration as code.” This philosophy states that any steps necessary to build your application should not be done by hand but instead written into code. Why? Several reasons:
You could forget manual steps, but you can store those written in code in a repo, so they are as safe as all your other source code.
When you keep the steps in your repo, you can easily share them with other team members.
Steps written as code can be executed by your computer automatically. This is quick and reliable, especially if there are multiple steps.
Now you know why migrations are important, let’s create one for the Band model.
# shell
(env) ~/projects/django-web-app/merchex
→ python manage.py makemigrations
python manage.py makemigrations
Migrations for 'listings':
listings/migrations/0001_initial.py
- Create model Band
The CLI output tells you that a new migration has been saved to ‘listings/migrations/0001_initial.py‘, and that its purpose is to “Create model Band” - what this actually means is that this migration is going to create a database table for the Band model.
How did it know to do that without me having to specify anything?
The great thing about this command is that it scans your models.py file for any changes and figures out what sort of migration needs to be generated.
Now that we have the migration (instructions) - we need to run them against the database.
Call migrate
With the CLI
(env) ~/projects/django-web-app/merchex
→ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, listings, sessions
Running migrations:
Applying listings.0001_initial... OK
Remember adding listings to the project'sINSTALLED_APPS
in the setup chapter? Django looked through each one of those installed apps for new migrations to run, found our new migration, and applied it - it ran those instructions against the database.
We’re finally ready to use our model to create some Band objects!
Save Objects to the Database in the Django Shell
In this section, we’re going to write code in the Django shell.
The Django shell is just a regular Python shell that is running your Django app. You can think of it as a place to try out code in real-time - every time you hit Enter, the line of code you just typed is executed. So, whereas code you type into a Python module/file can be executed many times over, the code you type into the Django shell is run just once and then forgotten about.
Let’s use the shell to create some Band objects and then save those objects to the database.
You can use my examples, or feel free to add your own favorite bands, musicians, or composers!
Open the shell using the command line utility:
(env) ~/projects/django-web-app/merchex
→ python manage.py shell
>>>
At the shell prompt ( >>>
), type the following code to import the Band model:
>>> from listings.models import Band
Hit Enter to run that line.
Next, let’s create a new instance of the Band
model:
>>> band = Band()
>>> band.name = 'De La Soul'
Take a look at the current state of the object by typing band
:
>>> band
<Band: Band object (None)>
The shell indicates a band object, but the id is None
- it has no id yet.
Let’s save that object to the database:
>>> band.save()
Then take another look at the state of the object:
>>> band
<Band: Band object (1)>
Now the id is1
.
Let’s do that again, this time giving the Band object a different name. You can reuse the band
variable and assign a new Band
to it:
>>> band = Band()
>>> band.name = 'Cut Copy'
>>> band.save()
>>> band
<Band: Band object (2)>
Let’s now try a different method. Here’s a one-line alternative that does the same thing:
>>> band = Band.objects.create(name='Foo Fighters')
You can see the object and the value of its name
field:
>>> band
<Band: Band object (3)>
>>> band.name
'Foo Fighters'
The database now contains three band objects. You can check like this:
>>> Band.objects.count()
3
>>> Band.objects.all()
<QuerySet [<Band: Band object (1)>, <Band: Band object (2)>, <Band: Band object (3)>]>
Hit Ctrl-D
to exit the shell.
You’ve now created a model, run the migrations so that it exists in the database, and then created and saved an instance of that model to the database. Check out the screencast for a refresher of all of these steps.
Let’s return to the view to display the band names on one of the pages.
Update the View to Display the Band Objects
So how can we get our objects back out of our database and into our pages?
Open up listings/views.py and find the hello
view function, which we left like this in the last chapter:
# listings/views.py
def hello(request):
return HttpResponse('<h1>Hello Django!</h1>')
In the previous section, you saw how to get all Band objects from the database in the shell: Band.objects.all()
. Let’s do the same thing in the view and store the objects in a variable:
# listings/views.py
...
from listings.models import Band
...
def hello(request):
bands = Band.objects.all()
return HttpResponse('<h1>Hello Django!</h1>')
The bands
variable now contains a list of all of the bands found in the database. That means it’s now possible to access each of the individual Band
objects by using Python’s index notation, like this:
# example code
bands[0] # for the first `Band` object...
bands[1] # for the next one…
bands[2] # and the next one...
Then, to access the “name” field of one of these Band
objects, you would call on the object’s name
attribute using Python’s dot notation - the same way you would with any other object:
# example code
bands[0].name # would return "De La Soul"
Let’s use these techniques to display the band names in our page:
# ~/projects/django-web-app/merchex/listings/views.py
...
from bands.models import Band
...
def hello(request):
bands = Band.objects.all()
return HttpResponse(f"""
<h1>Hello Django!</h1>
<p>My favorite bands are:<p>
<ul>
<li>{bands[0].name}</li>
<li>{bands[1].name}</li>
<li>{bands[2].name}</li>
</ul>
""")
To help with readability, we’ve:
Used triple-quotes (
"""
) to spread our HTML string over multiple lines.Made that string an “f-string” (
f"""
) to inject the band names into the string using{ ... }
placeholders.
Let’s take another look at this page in the browser: http://127.0.0.1:8000/hello
Our view is now able to retrieve data from that database and display it in one of our pages. Let’s go over these steps again in the screencast.
Let’s visualize what you’ve done in this chapter:
Now you are ready to create your own models and migrations!
Now You Try! Utilize Models and Migrations to Save Data to a Database
It’s your turn to add a new model to your application. This model is going to track listing
objects. It should have just one field called title
with a maximum length of 100 characters.
Your model will need an accompanying migration, which should be run against the database. You can then use the Django shell to insert at least three objects into the database.
Some examples of listings titles:
“ORIGINAL De La Soul tour poster - Fillmore Auditorium San Francisco November 2001.”
“Cut Copy gig T-shirt, Free Your Mind tour, 2013.”
“Foo Fighters - Big Me single promo poster, late 90's.”
“Beethoven - Moonlight Sonata - original manuscript EXTREMELY RARE.”
Finally, you should update your listings
view that you created in the last chapter so that it retrieves the listings
objects from your database and displays their titles in your page’s HTML.
Let’s Recap!
A model defines the characteristics and behaviors of an object that you want to keep track of in your application. It’s a lot like a standard class, but additionally, a model knows how to save (“persist”) its data to a database.
A migration is a set of instructions that move your database from one state to another, e.g., by creating a new table. You can use Django’s CLI to generate and run migrations for you.
You can use the Django Shell to insert new objects into your database.
In a view, you can retrieve objects from the database and display their data on our pages.
Using models - the ‘M’ of MVT architecture - we’ve saved data to our database, and we’re displaying that data on our pages. Now let’s look at the final element of MVT: the template.