Models
If you are building a dynamic application using a web framework, data storage, using a database is essential. Recall that the presentation layer is the layer that the user interacts with. Any data posted from the presentation layer needs to be persisted and also kept for retrieval for later use.
Model
The solution is to use a model. The object equivalent of a database table used in Django and acts as a single definitive source of information about your data.
Working with Database
If you are a developer on the back end of an application, working with databases can be achieved in one of two ways.
- The first way is to work directly in the database to create the required tables. Then in your application, you would need to create custom queries written in the Structured Query Language or SQL to store and retrieve the data.
- The second way is to use a framework. Youâve already learned that frameworks are designed to assist developers by providing them with a platform for rapid development and one-way developers can speed up their development is by using models to interact with the database.
Models
A model is the single definitive source of information about your data. It contains the essential fields and behaviors of the data youâre storing. Generally, each model maps to a single database table.
Models are an integral part of the Django framework.
The structure of model
Each model is a Python class that subclasses django.db.models.Model
.
Each attribute of the model represents a database field. This means that instead of having to write a custom query for adding and retrieving database records, you can use a model to do it instead.
Django gives you an automatically generated database access API to access the database with Python code.
Essentially, you can think of a model as a Python object and models help developers create, read, update, and delete objects, commonly called the CRUD operations.
Making a table using SQL syntax
You may recall that to create a table in a database using SQL, you would need to write a query using the create table syntax. When the code runs, a table called user will be created with three columns, ID, first name, and last name.
Making a table using django model
To do this using a model in Django, you define a class that will subclass the django.db.models.Model
. You may notice that the ID or a primary key is not specified in the class. This is because Django automatically adds it, but you can override it if needed.
WARNING
At this point, itâs important to know that you cannot create a database table by only defining a model class in Python. To complete this process, you need to use something called migrations.
Django automatically provides all these methods (CRUD operations) out of the box.
Create
You may recall that creating records in SQL requires you to use the insert statement.
In Django, creating records requires you to create a new object from the class user and then persisted using the save function.
Read
Un SQL to retrieve information, you need to write a SQL query using the select statement.
In Django, you can use the get method which is bound to the user.objects
.
Update
Suppose you have a table of users with a user named John Jones with the ID of one. You want to update the userâs last name to Smith. In SQL, you use the update statement to update an existing record in a database.
To achieve the same result in Django, you use the methods get and save. The code works by checking if a user exists with the ID of one and then updates the userâs last name to Smith.
Delete
With SQL, the delete statement is required to delete records in the database.
To achieve the same result with Django, you use the delete method.
Itâs important to note that these are only some of the many methods Django provides when working with models.
Model relationships
In this reading, you will explore the different types of relationships between Django models.
Primary key
In a relational database, each table that represents an entity has one column that has a unique value for each row. Such a column or field is known as the Primary Key.
If the primary key of one table appears as one of the fields in another table while having its own primary key, then it is called a Foreign Key.Â
For example, in a Products table, the ProductID
field is its primary key.
In the Customersâ table, the ProductID
field, which refers to the product purchased by the customer, becomes the foreign key.
The idea behind designing related tables is to avoid data redundancy unnecessary repetition of the same data in many rows and ensure data integrity.
If the unique ProductID
in the Customersâ table is replaced by a longer naming convention for the product field, it will have to be entered every time a customer buys the product. This can lead to typing errors.
Similarly, if a productâs ID is referred to in the Customersâ table and is removed, other product details, such as price, will not be available.
Relational databases have a mechanism to prevent the deletion of the primary key if it is being used in the related table so that the data integrity is intact.
Since the Django models are mapped to the corresponding tables in the database, you can define a relationship such as this between the two model fields.
Types of Relationships
There are three types of relationships that exist:
- One-to-One,
- One-to-Many, and
- Many-to-Many.
Letâs explore these by beginning with a One-to-One relationship.
One-to-One relationship
If a primary key is in one model, and only one record exists in the other related model, the two models are said to have a one-to-one relationship.
Letâs use an example of a college model and a principal model. A college can have only one principal or it can be similarly phrased as one person can be a principal of only one college.
The college model can be described as follows:
In the principal model, you must provide the CollegeID
field as the foreign key. The on_delete
option specifies the behavior in case the associated object in the primary model is deleted. The values are:
- CASCADE: deletes the object containing the
ForeignKey
- PROTECT: Prevent deletion of the referenced object.
- RESTRICT: Prevent deletion of the referenced object by raising
RestrictedError
The principal model has the following field structure:
When you run a migration on these models, respective tables are created with equivalent SQL queries:
One-to-Many Relationship
In a One-to-Many relationship, one object of a model can be associated with one or more objects of another model. For example, a teacher is qualified to teach a subject, but there can be more than one teacher in a college who teaches the same subject.
The subject model is as below:
The teacher model has its own primary key. It has a Foreignkey
relating this model with the subject model.
The following SQL queries will be executed when you run the migration:
Many-to-Many Relationship
In a Many-to-Many relationship, multiple objects of one model can be associated with multiple objects of another model.
Letâs redefine the relationship between the subject and teacher models in the above example. If more than one teacher can teach the same subject, a single teacher can teach more than one subject. So, there is a Many-to-Many relationship between the two. Django implements this with a Many-to-Many Field type. Letâs use it in the subject model.
The teacher model is straightforward.
The design of the Subject model class reflects the Many-to-Many relationship.
When the migrations are done, the following SQL queries will be executed to establish a many-to-many relationship.
CREATE TABLE âmyapp_teacherâ (âTeacherIDâ integer NOT NULL PRIMARY KEY, âQualificationâ varchar(50) NOT NULL, âemailâ varchar(50) NOT NULL);
In this reading, you learned about the various types of relationships between models and how Django handles them.
Creating models
Iâve already created a project called menuproject
and an app called menuapp
. To build a model, I write code in the models.py
file.
It gives error because I have not added the model inside the settings.py
file.
So once Iâve added the model to the installed apps list, I need to perform something called migrations.
Notice that it creates a model, menu and a python file. If you go to the python file, you can see that django internally has created the columns and the table menu using the built in SQLite database.
Now Iâm ready to go back inside the shell and work with the menu model I created.
Menu.objects.all()
returns all the entries in the database.
Notice that there are two objects but this is not very informative as only the names of the menu objects one and two are displayed. Django provides a way to change this using something called custom methods.
For example, I can use one of the building custom methods and customize the string.
Now that Iâve demonstrated how to create a database table and add entries to it, let me demonstrate how to update entries.
Suppose I want to access an entry and update it. To do this, I can use the get method and pass the primary key of value to which refers to the entry of taco.
Another option to view and update the database is using your browser to access the django admin portal. However, itâs also important to understand how the code works internally as Iâve demonstrated.
Migrations
In the world of web application development, application requirements constantly change and itâs a developerâs job to implement these changes. For example, a common task is to alter the data model of the application. To do this in Django, you use something called migrations.
Recall that Django is designed to work with a relational database management system like PostgreSQL, MySQL, or SQLite, and in a relational database, data is organized in tables.
By now, you know that you can use models to represent data tables stored in the database. Recall that when using models, Django provides many methods that allow you to add, update, and delete data right from the code without having to write SQL.
This is made possible by using something called an object-relational mapper, or ORM.
For now, just know that it maps the relational database to objects represented as Django models. The models define the database fields which correspond to the columns in their associated database tables.
For example, if you have a model called User, you know it will represent a table called User and each attribute of the model has a column representation in the database. So, in the Python code, if the user class has an attribute of first_name
, the table will have a column of first_name
.
Itâs common that during the life cycle of the development of the application, changes to the structure of the database or schema will be required.
For example, the initial model may need to be extended with additional attributes. This means adding a new attribute, which will add a new column from the perspective of the database. Or, suppose you need to perform a different operation, like changing a column name or even deleting a model.
For these operations to work, Python uses something called database migrations.
Migration
Migrations are how Django records changes made to models and implements these changes to the database schema. Migrations are tied into Django models and stored as migration files in a Migrations folder inside each app.
How migration works
Suppose you wanted to add a new column called City to the User table. Without an ORM like the one Django provides, a developer must login to the database and run a SQL alter statement. You may recall that you can use the alter statements to alter a specific table to add a column of whatever type is required. When the statement runs, the User table updates with another column called City.
In Django, the User table is created using a model which you may recall is a class-based representation of the User table in the database. So instead of writing the SQL query, you only need to add the new attribute to the model then run the migration scripts to implement the changes. Once the migration scripts run, the changes are applied.
Django provides a list of CLI commands that allows you to apply the migrations.
First, you must create a migration script and then apply the migrations.
The migration script is a set of instructions on what models to create against the database. You apply the change to the model, run the migration file, and Django will take care of the rest.
You do not need to write any SQL as the application handles everything.
Why use migrations instead of SQL
Migrations do more than just implement SQL commands. They can help with syncing issues, version control, and database maintenance. Itâs good to think of migrations as a version control system for your database schema.
Syncing issues
With migrations, you have less possibility of syncing issues between what the model has and what the database contains.
When working in a team, each developer usually has their own local copy of the database so they can code and test against it. Migration scripts are kept in the code repository. When a developer on the team makes changes, they run the migration script to update their local copy of database to the latest version.
Version control
All the changes are kept in version control, which provides an entire history of changes across the application. Developers can also use this to determine what changes have been added and by whom. Generally in application development, the more you can track changes that occur in the app, the fewer problems you will encounter.
The alternative is running scripts in the database directly, which is usually more problematic as it is outside version control.
Ease of maintenance
Along with helping syncing issues and version control, maintaining all the database changes from the code base makes it easier for the development team. They donât have to worry about creating SQL queries directly against the database or where to store these files so all the developers can run them.
How to use migrations
Django translates the models into respective database tables in the backend database with a mechanism known as migration. It also propagates any changes in the model structure such as adding, modifying or removing a field attribute of a model class to the mapped table.
Djangoâs migration system has the following commands:
makemigrations
migrate
sqlmigrate
showmigrations
Djangoâs migration is a version control system. Whenever you add a new model or effect changes in an existing model, you need to run the makemigrations
command. It creates a script for making changes in the mapped table. Every time you run the makemigrations
command and Django detects the changes, a script with its name and version number is created. To implement the changes according to the migration script, you need to run the migrate
command.
Migrating Models of INSTALLED APPS
When you create a Django project with the startproject
command, certain apps are installed by default. These apps are listed in the INSTALLED_APPS
section in the projectâs settings.py
file.
Data needs to be stored via these apps for their functionality to work. For example, the auth
package controls the users, groups, and permissions, so there must be corresponding tables created in the database. Django uses the SQLite database by default. For that purpose, you run the migrate
command.
Then, the tables required by the INSTALLED_APPS
are created.
Letâs create an app inside our Django project.
This creates a myapp
package folder inside the outer myproject
folder. Inside myapp
, a migrations
package is also created, which is empty to begin with.
Using the makemigrations
command
Open the models.py
file and add a person model to it.
The first step towards creating the Person table in the database is to run the makemigrations
command.
Notice that in the migrations
package, a migration script 0001_initial.py
, is created. It indicates what the script intends to do, which is: Create model Person
.
If you open the migration
file, youâll find a migration class in it.
As mentioned above, you need to run the migrate
command to apply the tasks in the migrations
file to be performed.
Have a look at the tables in your database db.sqlite3
. The person table with three fields can be seen in it.
Version control
Now, letâs modify the person model class by changing the name
field to Person_name
and running makemigrations
again.
A second migration script is created in the migrations
folder. Before finalizing the change, add a new field â age â in the person model and run makemigrations
again.
Showmigrations
command
Now there are two unmigrated changes in the model. Run the showmigrations
command:
The initial migration (file numbered 0001) has already migrated. The X mark is indicative of this. However, the next two migrations donât show the X mark, which means they are pending. If we run the migrate
command, both modifications will be reflected in the table structure.
As mentioned earlier, Djangoâs migration mechanism provides efficient version control. You may want to fall back upon the table structure before adding the age
field. Run the migrate
command and specify which migration file to be used so that the migrations after it will be undone or unapplied.
sqlmigrate
Command
Lastly, the sqlmigrate
command shows the SQL query or queries executed when a certain migration script is run. For example, the first migration over the myappâs
person model is intended to create the person table. The sqlmigrate
command for this script shows the CREATE TABLE
statement for this purpose.
In this reading, you learned about when to use migrations, best practices and that the migration system in Django manages data creation and modification very effectively and efficiently.
Working with Migrations
Iâve already created a project in VS code containing an app called myapp.
Inside the models.py file, Iâve created a class called Menuitems
. Recall that this class is equivalent to a table in SQL and contains three attributes, name, course, and year with respective fields.
The difference
makemigrations
is Djangoâs way of preparing the changes to be made in the model. For example, it creates a database such as this one named db.sqlite3. So you can think ofmakemigrations
as the command that generates the SQL commands- and
migrate
as the command where those SQL commands are executed.
Once Iâve run this command, notice that a folder called migrations is created inside the app folder, which consists of the file that keeps a record of the migrations. If I open the file, notice that the code contains the table columns, names, and auto assigned primary key called ID.
Changing the model
What if I want to make some changes to the model? For example, suppose I want to change the attribute course to category and save this file.
For this change to take effect,I have to run the makemigrations command again. Notice that Django displays a message that asks, âWas menuitem.course renamed to menuitem.category?â To confirm, I type yes and press âEnterâ.
Now, notice that another file is created inside the migrations folder. If I open that file, notice that it contains the code changes performed in that migration.
Display all migrations performed
To do this, I can run the command python manages.py and then show migrations.
The X symbol represents the commits to the migrations.
Revert back
I can do this by typing python manage.py migrate, then I need to specify the name of the app and the final number, for example, 0001.
But before I execute, I can add a flag such as plan. Django will then display the changes it will revert to.
This time, I execute this command without the plan flag. And notice that even if the changes are not displayed in the Python file, the changes have been reflected in the database I created.
sqlmigrate
I can run this command against some migrated version. Notice that when I execute it, the corresponding sql commands are displayed for the migrations I have performed.
A history of changes
Every model created in the project provides a full history of how it was created, when it was added, and any changes that have occurred. Web application development requirements tend to change quite a bit in small increments.
For example, adding an extra attribute to a model or changing an attribute name. Additionally, there are occasions when multiple users use more than one database and migrations ensure schema changes are applied and updated on each database.
In Django, a developer must create the change directly in the model, then apply the migration by using the migration scripts.
Another important advantage of using migrations is to avoid repetition. Once you create some model, writing SQL queries to create corresponding databases for it is repetitive. Migrations generated from the models help prevent duplication of efforts. This is in line with one of the core principles of Django, donât repeat yourself (DRY).
How django keeps history
It all begins with the file structure, migration files are stored in a migration folder. If you expand the migrations folder, notice that it automatically updates the file system after the migration has run. You can explore the details of the migrations using the show migrations command.
Django automatically generates the file names in line with the actions performed in the given migrations or the timestamp.
The X symbol represents the status of applying migrations after making them.
After applying migrations, Django does not apply a new migration to the same database again, unless it detects changes.
Django migration table
Behind the scenes, Django creates a new table called Django migrations. With reference to the migration files.
A new row is inserted after each migration tracking the changes, apps and the timestamp of the migration.
- The first column is the ID and this is auto-incremented based on the position in the table.
- The second column is the app that the migration is associated to. Recall that in Django, you can have multiple applications inside the project.
- The third column is the name and refers to the file name of the migration.
- The final column is the timestamp of when the migration was applied.
Every time a migration script is run, this table is updated with the latest changes. This also means that itâs checked prior to the migration script running. This is done so that it knows which scripts have been run and which ones need to be applied.
Migrations can also be applied to a specific app by placing the app name after that make migrations command.
Contents of a migration file
Migration files are basically Python code. Inside the migrations class, it will typically contain two important sequences or list items, such as dependencies and operations.
- Dependencies refer to the previous migration, that must be applied before this.
- Operations refer to actions performed in the given migration. Some of the commonly used operations are:
CreateModel
, which creates a model and drops a table.DeleteModel
, which deletes a model and drops a table.AddField
, which adds a database column and field definition creations are additions.AlterField
, which creates a database column and field definition changes.AddIndex
, which creates a database index.
So for example, an operation such as DeleteModel
will generate a corresponding SQL query such as DELELETE TABLE Customers
.
Models using Foreign Keys
Foreign keys
In Django, foreign key is an ORM field representing a database table column. You use it to create the relationships between tables in your database.
Imagine the scenario of building an online menu for the Little Lemon restaurant. The solution begins with creating a table to add the menu items for the web page.
Now, Little Lemon is a restaurant that offers many cuisines. In placing each cuisine item in its correct category requires some skill. To do this successfully, start by creating another model for categories and assign the different categories to each of the menu items.
Letâs begin by selecting the models.py file. Here, you need to create two models. The first model is for the menu category and the second model is for the menu. Later you will add subcategories in the menu category and use the foreign key to reference these categories.
Itâs important to know that adding both models is done the same way as adding models independently.
Write the models.ForeignKey
command in the category_id
. Inside the foreign key are two required fields.
The first field is the class for the model to connect to. And the second field is the settings that enables on delete. So itâs defined as on delete equal to models.PROTECT
. Additionally, add another argument called default=none
.
The next step includes updating the admin.py file by actioning the required imports. Next, itâs time to register the models. Note, that the utility becomes more evident later in the Django admin lesson.
For now, ensure that the settings.py file in the app configuration is updated.
Go ahead and run the server, followed by performing the migrations. Notice that the output includes two models that are migrated.
Finally, run the command python3 manage.py migrate
.
The next step is to check the database. So go to db.sqlite3, Right Click and select Open Database, scroll down to SQLITE EXPLORER and select myapp_menu
. For this example, assume that there are entries added to the database.
Notice that there is a fourth field called category_id_id
. This field has ID numbers that match the respective categories in the myapp_menu
table.
Now, letâs make this more intuitive by adding another attribute called related_name=
and assign it the valued labeled category_name
.
This means that the myapp_menu
now lists the category name instead of category_id_id
.
This is noticeable when running migrations again.
The failed category on the menu is altered. Notice that with on_delete=models.PROTECT
selected, no menu items will be removed with any category that is deleted in the category table.
Object Relationship Mapping - ORM
What is ORMÂ
Usually, the type of system used in an Object-Oriented language such as Python contains types that are non-scalar and every time, they cannot be represented only in primitive types such as integers and strings.
On the other hand, data types in tables of a relational database are of primary types, that is integer and string.
Therefore, the program needs to convert objects in scalar data to interact with a backend database.
Object-oriented programming languages use Object Relation Mapping (ORM) to interact with Structured Query Language (SQL), both of which are incompatible.
The ORM layer maps a class to a table in a relational database, with its attributes matching the tableâs field structure.
The ORM library lets you perform the database operations in an object-oriented way instead of executing raw SQL queries.
This allows you to focus more on the programming logic than the backend database operations.
Object Relational Mapping or ORM is the ability to create a SQL query using object-oriented programming language such as Python. This enables a quick turnaround time in fast production environments that need constant updates.Â
Each model is a Python class that subclasses django.db.models.Model
Each attribute of the model represents a database field.âŻEssentially you can think of a model as a Python object, and models help developers create, read, update and delete objects, commonly called the CRUD operations.
Django has its own ORM layer. Its migration mechanism propagates the models in database tables.
You need to construct a QuerySet
via a Manager of your model class to retrieve objects from your database.
QuerySet
Letâs try to understand how QuerySet
is constructed and handled with an example. To begin with, add the following models in the Django app named demoapp
.
The idea is to create two tables, Customer and Vehicle, with a one-to-many relationship. Apply the migrations and you will see these two tables in the projectâs database.
Next, open the Interactive shell.
It is important to know that these commands are the same if you are on Windows or Mac.
(djenv) C:\djenv\demoproject>python manage.py shellÂ
Create an object of the Customer class. Give a string parameter to the constructor. The save()
method of the models.Model
class creates a row in the Customer table.
Adding a model object
The Customer.objects
gives the Manager of the model. It handles all the CRUD operations on the database table. For example, an object can also be created with the create()
method as follows:
The create()
method actually performs the INSERT
operation of SQL.
Now, let us add two objects to the Vehicle model. Note that one of the fields in the Vehicle model refers to an object of the Customer table as ForeignKey
. Fetch the Customer object with a primary key = 2.
This object is used as the value of the customer attribute in the Vehicle object.
Similarly, add two vehicles for Customer âHenryâ.
Fetch model objects
A QuerySet
represents a collection of objects from your database. It represents a SELECT
query. To fetch all the objects, use the all()
method of the Manager.
The all()
method returns a list of objects. You can iterate over it with the usual for loop or list comprehension technique.
You can apply filters to the data fetched from the model. This is used to fetch objects satisfying the given criteria. In SQL terms, a QuerySet
equates to a SELECT
statement, it is like applying a WHERE
clause.
For example, use the following statement to retrieve all the customers with names starting with âHâ.
Similarly, you can retrieve the objects of the Vehicle model. Remember that the Vehicle object refers to a customer object. You can retrieve the attributes of the related customer as follows:
Updating and removing a model object
To update an object, such as changing the Customerâs name from Henry to Helen, assign a new value to the name attribute and save.
Similarly, the delete()
method of the model manager physically removes the corresponding row in the modelâs mapped table.
This way, you can perform the CRUD operations on a database table using the QuerySet
API instead of executing raw SQL queries.
Using ORM
When building web applications, developers use databases to store data and write sequel queries to fetch and manipulate that data as applications grow in size and complexity. So too can the amount and complexity of the sequel queries. To assist developers, Django provides a feature known as object relational mapping, or ORM, that automatically creates the required sequel queries.
ORM
Object relational mapping is an abstraction layer created to facilitate interaction between the programming language and databases. This allows programmers to use the sequel databases without needing to write sequel queries. A structured map is created internally by ORM, that generates sequel code for a given relational database, by observing the changes made to the data objects. ORM can be accessed by using the shell command.
QuerySet
Previously you may have noticed how each row entry added for a given model creates an object, you may recall the output had the prefects query set.
QuerySet
A query set is a collection of such objects. For a given model used in Django and Django uses a query set to retrieve and manipulate these objects from the database.
For example, suppose you have a model called customers. You can access the contents of this model by running the command:
This command returns the output as a query set. The list will contain the entries for the different objects corresponding to the row entries in a database.
For every sequel query that can be constructed, there is a corresponding command. These commands are a part of the QuerySet API.
So for example, if you want to join multiple parameters using the WHERE
or limit clauses in sequel you can use the filter
function and pass the conditions to it as arguments. This will select the entry for customers who have reserved a table for four people.
Django functions for queries
Considering the variety of complex queries that can be constructed in sequel, Django has several functions that support these operations. They can be categorized as follows based on the required logic to run on the query set:
- methods that return new query sets
- operators that return new query sets
- methods that do not return query sets
WARNING
User double quotes for string you use in the filter function.
Additional resources
The following resources will be helpful you learn more about different concepts related to Models and Migrations.
Models â official documentation
Migrations â official documentation
Other Model Instance methods (including the String Dunder method)
Detailed overview of Migrations
PythonDjangoDatabaseOOPframework
Previous one â 7.Creating URLs and Views | Next one â 9.Models and Forms