Working with Django models (Django ORM)
If you cannot or do not want to save data dynamically in your web application, then there is no point of using a great framework like Django. You could use plain old HTML, CSS, JavaScript to serve your content as a static website. Usually we save our data in web applications with the help of some kind of database. Most of the time we use relational databases.
When a relational database comes into play there comes along with it another language—a query language. Usually we use SQL or Structured Query Language to communicate with the database system. SQL poses a lot of problem for most of the people (usually who are primarily not DBA). First of all one needs to learn another language. Different database systems use different dialects of SQL and that brings another trouble maker to the table. Another headache is, where there is SQL there is a risk of SQL injection which is a great cyber security threat to your web application.
The most fundamental problem it brings to the table is, we not only work with two different languages but also we have to mix and match them. Databases are built upon the concept of tables whereas Object Oriented Programming languages like Python revolve around objects. In Python we create relation between objects with the help of object reference and we can create an object graph very efficiently. A table does not easily go with that. We have to make both go with each other, and this creates more problems.
An ORM system can fill the gap and solve the problem described above. With the help of Django ORM we do not need to think about SQL syntaxes of various database CRUD operations. We do not need to construct long SQL queries to query the database, nor mix and match two different systems. Instead, we think the Pythonic way—we create classes that correspond to database tables. We create objects from those classes and each such objects represents a row. Attributes of the object represent table columns. To save an object we do not need to write any SQL queries—instead we call methods on the objects. We don’t even need to create a database schema. With two lines of management command you can create and update database schemas. Django keeps record of schema changes, so you can go back and forth in time with your schema without the pain of mastering another language or a set of tools.
Configuring the database
Before we can use a database we need to configure it. By default Django uses SQLite which needs no extra configuration. The default setting looks like the following:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
For SQLite backend you do not need to provide any connection URL, neither do you need to provide a database username and password. But what if we want to use MySQL or other relational database systems? No need to worry, no need to panic. It is just a few lines of code.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'DB_NAME',
'USER': 'DB_USER',
'PASSWORD': 'DB_PASSWORD',
'HOST': 'localhost',
'PORT': '3306',
}
}
All the fields are self explanatory. If you do not have database on your local machine but on a remote server then you can use that server's IP address instead of localhost as the host.
Models
Models are the pure Python classes inherited from Model class that represents a table structure. The Model class can be found inside django.db.models module. We usually create these classes inside the app's models.py script. Let's create a model class that will represent a person.
# models.py
from django.db import models
class Person(models.Model):
pass
You have successfully created a model and with the help of this you can create database schema and persist data to the database. But wait! There is no field and as a result no column will be there. But we cannot just create arbitrary fields and imagine that those fields will be persisted in the database. We need to provide special properties on model classes to map fields to database table columns. For every type of column we have a corresponding type in Django ORM. See example:
# models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=64)
Now, we have an usable model. name attribute is the instance of CharField that corresponds to VARCHAR in relational database. Let not talk about SQL things much and concentrate on our OOP model of working with database.
# models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=64)
age = models.IntegerField()
height = models.FloatField()
To represent Python integer we have IntegerField, and to represent float we have FloatField. There are a lot of such classes to fulfill all our requirements. Look at the official reference guide to learn about them, and maybe even keep it under your pillow to have a quick look.
Creating Migrations
Now we have a model that we can use, but it’s just a class. There is no existence of this class in the database. We have to tell Django to create migration files that will eventually be used for creating corresponding database schema.
To create the migrations open the command line and run the command.
python manage.py makemigrations
The following output is shown
Migrations for 'app1':
app1\migrations\0001_initial.py
- Create model Person
But still nothing is in the database yet. We just made the migration file called 0001_initial.py - we need to apply it with the following command.
python manage.py migrate
The following output is shown on my machine.
Operations to perform:
Apply all migrations: admin, app1, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying app1.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying sessions.0001_initial... OK
Aside from the migration from our app, a lot of other migrations are applied too. Those apps are added by default in our settings file. Look at the the migration that we are expecting to be migrated.
Applying app1.0001_initial... OK
We have successfully created tables in our database. If you are confused, check your database.
Creating a row
To create a row in the database table we have to instantiate Person class and after populating the attributes we need to call the save method.
To work with the models we are not going to create views at this time. We are going to use Django shell this time. It will help you test your models interactively. We will run CRUD operation on models when we have learned about Django forms in future articles. To start the Django provided shell run the following command.
python manage.py shell
Import the Person class, instantiate it, populate some data and call save method.
>>> from app1.models import Person
>>> p1 = Person()
>>> p1.name = "Jhon"
>>> p1.age = 23
>>> p1.height = 5
>>> p1.save()
>>> p1.id
1
A row is added to the database table and it's id is 1. So, we have successfully created a row in the database. Let's create two more.
>>> p2 = Person()
>>> p2.name = "Jhon 2"
>>> p2.age = 24
>>> p2.height = 6
>>> p2.save()
>>> p2.id
2
>>> p3 = Person()
>>> p3.name = "Jhon 3"
>>> p3.age = 25
>>> p3.height = 7
>>> p3.save()
>>> p3.id
3
Retrieving Data
Retrieving a row or an object from the database is as simple as calling few methods. Every model class has a manager on it that is called objects; we need to use the get() method on it for finding one record. We already know that the id of the first record we inserted is 1. Before we proceed I want to modify the Person class and restart the shell. I want to create a __str__() method on Person class to show it's data easily on the shell.
# models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=64)
age = models.IntegerField()
height = models.FloatField()
def __str__(self):
return "Name: %s, Age: %s, Height: %s" % (self.name, self.age, self.height)
Now let's retrieve our first record inserted.
>>> Person.objects.filter(name="Jhon")
<QuerySet [<Person: Name: Jhon, Age: 23, Height: 5.0>]>
>>> p1 = Person.objects.get(id=1)
>>> p1
<Person: Name: Jhon, Age: 23, Height: 5.0>
Look at the result, we have got the result we expected. You can get individual data by referencing individual attribute on the object (here p1)
You can get all rows at once:
>>> Person.objects.all()
<QuerySet [<Person: Name: Jhon, Age: 23, Height: 5.0>, <Person: Name: Jhon 3, Age: 25, Height: 7.0>, <Person: Name: Jhon 2, Age: 24, Height: 6.0>]>
You can retrieve rows by name:
We can filter by various criteria. Take a look at the reference documentation to get all of them.
Updating data
After retrieving a row as an object you just need to change the value of the attributes and call the save() method to update the data. We already retrieved first Person added as p1.
>>> p1 = Person.objects.get(id=1)
>>> p1.name = "Jhon 1"
>>> p1.save()
>>> Person.objects.get(id=1)
<Person: Name: Jhon 1, Age: 23, Height: 5.0>
Notice that the name of the first person added is changed. We confirmed that by calling the get method again.
Deleting data
Deleting data is as simple as calling delete on persisted model instance.
>>> p1 = Person.objects.get(id=1)
>>> p1.delete()
(1, {'app1.Person': 1})
>>> Person.objects.all()
<QuerySet [<Person: Name: Jhon 3, Age: 25, Height: 7.0>, <Person: Name: Jhon 2, Age: 24,
Height: 6.0>]>
>>>
Look at the all queries now. There is no existence of the first person added in the database.
Learning more
ORM is not such a small topic to be covered in a single article. This article was for creating a strong foundation on Django ORM. I tried to show you most aspects of it with examples and using simple language. To learn more you need to practice a lot and consult the official reference documentation.
*Stop by the homepage to search and compare SDKs, Dev Tools, and Libraries.
Recent Stories
Top DiscoverSDK Experts
Compare Products
Select up to three two products to compare by clicking on the compare icon () of each product.
{{compareToolModel.Error}}
{{CommentsModel.TotalCount}} Comments
Your Comment