Django ORM Basics

Having learned the art of creating models, lets now shift our attention on how to access the data stored in the database. Django ORM provides an elegant and powerful way to interact with the database. ORM stands for Object Relational Mapper. It is just a fancy word describing how to access the data stored in the database in Object Oriented fashion.

Start Django shell using the shell command.

To work with the database inside the shell, first, we have to import necessary models. In this section, we will be working on models stored in the blog app, so let’s start by importing all the models in the blog app.

At this point, the tables corresponding to these 4 models are empty.

Let’s start by creating an Author object.

Try printing the variable a and you will get the following output:

You can access the attributes of an object using the (.) dot operator.

Notice that at the time of creating Author object we didn’t provide any value to created_on and last_logged_in field because these fields have auto_now_add and auto_now set to True respectively. As a result, Django will automatically provides the current date and time at the time when you save the object to the database. However, If we hadn’t set auto_now_add and auto_now parameters then we would have to pass values to created_on and last_logged_in fields as follows:

At this point, the object pointed to by variable a exits only inside the Django shell. To save the object to the database call the save() method on the object.

Recall that every model we define inherits from models.Model class, this is where the save() method comes from.

To view this newly added object open blog_author table inside Navicat Premium.

author object in the database

Similarly, models.Model class also defines a delete() method to delete an object from the database.

Let’s delete the object from the database.

This code removes author tom from the database. However, it still exists inside the shell.

Indeed, the object exists in the shell.

Defining __str__() method on model

At this point, if you try to print Author or any other Model object inside the shell. You will get output like this:

Not very helpful. Right? Is there any way to change it?

We can change this behavior easily by implementing a __str__() method in the Author model.

A __str__() is a special method which tells Python how to display an object in the human-readable form. Open file inside the blog app and update it as follows:


While we are at it, let’s add __str__() method to Category, Tag and Post model too.


Does this ring a bell? You might say “We are changing our models so we should run makemigrations right ?”.

Well No! Most of the time, we run makemigrations command only in the following two cases:

  1. When we add/modify fields in the model.
  2. When we add/modify Meta classes (we will discuss this later).

In fact, adding/modifying methods to models are not even considered as changes. You can test this by running the makemigrations command.

After adding __str__() to file, if you try to print Author object you would get the same output as before.

In order for the changes to take effect, exit the Django shell by hitting Ctrl+Z (Windows) or Ctrl+D (Linux) and start it again using python shell command.

Import necessary models and create a new Author object.

Now let’s try printing the object inside the Django shell.

That’s much better. isn’t?

Save this object to the database using the save() method.

When you save an object the primary key is assigned automatically. Once an object is saved into the database. You can refer to the primary key using id or pk attribute.

If you want to alter the value of attributes of an object just assign a new value and call the save()method again.

These changes are not yet saved to the database, you have to call save() to make the changes permanent.

Database Access through Managers

Django by default adds a manager called objects to every model class. The objects manager helps us to interact with the database in complicated ways. The objects manager is the most common way Django developers interact with the database.

To access objects manager type model class name followed by the (.) dot operator then the objects manager itself. For example:

As you can see objects is just an instance of django.db.models.manager.Manager class. The objects manager provides a whole range of methods which allows us to interact with the database easily.

Let’s discuss some important methods of objects manager.

The create() method

The create() method allows us to create and commit object to the database in one go, instead of separately calling the save() method. For example:

The bulk_create() method

The bulk_create() method allows us to create and commit multiple objects in one step. It accepts a list of objects. For example:

At this point, blog_author table should looks like this:

blog category table

The all() method

The all() method fetches all the records from the table. For example:

The above code fetches all the records from the blog_author table.

The all() method returns a QuerySet object. A QuerySet object looks a lot like a list, but it is not an actual list, in some ways, it behaves just like lists. For example, you can access individual members in a QuerySet objects using an index number.

Although r points to an object of type QuerySet but r[0], r[1], r[2] and so on, points to an object of type Author.

It is important to note that some methods of objects manager return QuerySet while some do not.

QuerySet is iterable just like a list. You can use a for loop to iterate through all of the objects in a QuerySet object.

The count() method

The count() method returns the total number of records in a database table.

The Author.objects.all().count() also returns the same thing.

Filtering records using the filter() method

Most of the time you would only want to work with a subset of data. Django provides a filter() method which returns a subset of data. It accepts field names as keyword arguments and returns a QuerySet object.

Author.objects.filter(name='tom') translates to SQL something like this:

As database has only one record where name is 'tom', the QuerySet object contains only a single record. If we had two records where name is 'tom' then filter() would have returned a QuerySet object containing two Author objects.

Similarly, Author.objects.filter(name='johnny') translates to SQL rougly as follows:

As there are no records where name is 'johnny' an empty QuerySet is returned.

We can also directly print the raw SQL Django uses to query the database using the query attribute of the QuerySet object.

Matching performed using keyword arguments are case-sensitive.

The last query returns an empty QuerySet because there are no records where email is "", although there is a record where name is "".

You can also pass multiple keyword arguments to the filter() method.

This translates to SQL roughly as follows:

Django Field Lookups

In addition to passing field names as keyword arguments. You can also use something called lookups. Managers and QuerySet objects come with a feature called lookups. A lookup is composed of a model field followed by two underscores (__) which are then followed by lookup name. Let’s take some examples.

__contains lookup

Here __contains lookup finds all the records where name field contains the word "ke".

Author.objects.filter(name__contains="ke") translates to SQL roughly as follows:

Matching performed by __contains lookup is case-sensitive. If you want to perform case-insensitive match use __icontains. However, SQLite doesn’t support case-sensitive LIKE statements. As a result, __contains and __icontains returns the same result.

__startswith lookup

The __startswith lookup finds all the records whose name field start with "t". There also exists a complementary lookup called __endswith.

Here __endswith lookup finds all the records whose email ends with "com". Both __startswith and __endswith are case-sensitive. Their case-insensitive equivalents are __istartswith and __iendswith.

__gt lookup

here __gt lookup finds all the records whose id or primary key (pk) is greater than 3. There also exists a complementary lookup called __lt.

Here __lt lookups find all the records whose primary key is less than 3. There are two more similar lookups called __gte and __lte which finds records which are greater than or equal to and less than or equal to respectively.

Retrieving a single record using the get() method

The filter() method described in the above section returns a QuerySet, sometimes we just want to fetch a single record from the table. To handle these situations objects manager provides a get()method. The get() method accepts same parameters as filter() method but it returns only a single object. If it finds multiple objects it raises a MultipleObjectsReturned exception. If it doesn’t find any object it raises DoesNotExist exception.

Notice the difference between the output of get() and filter() method. For the same parameter they both two different results. The get() method returns a instance of Author while filter() methods returns a QuerySet object.

Let’s see what happens, if get() method encounters multiple records.

Here get() method raises a MultipleObjectsReturned because there are multiple objects in the database that matches the given parameter.

Similarly, if you try to access an object which does not exist then the get() method will raise a DoesNotExist exception.

Ordering Results

To order result we use order_by() method, just like filter() it also returns a QuerySet object. It accepts field names that you want to sort by as positional arguments.

This code retrieves all Author objects ordered by id in ascending order. The above code translates to SQL roughly as follows:

It turns out that we can chain methods which returns QuerySet objects. Doing so allows us to modify the database query further.

This code retrieves only those Author objects whose id is greater than 3 and then orders those authors by name in ascending order. The above code translates to SQL roughly as follows:

To reverse the sorting ordering add minus(-) sign before the field name like this:

The above code translates to the SQL roughly as follows:

You can also sort the result by multiple fields like this.

This code will sort the result first by name in ascending and then by email in descending order

Selecting the fields

When you run a query to database like this:

It returns data from all the fields (columns). What if we want data only from one or two fields ? The objects manager provides a values_list() method specially for this job. The values_list() accepts optional one or more field names from which we want the data and returns a QuerySet. For example:

Notice that the values_list() method returns a QuerySet where each element is a tuple. And the tuple only contains data from the fields which we have specified in the values_list() method.

The objects manager also provides an identical method called values() which works exactly like values_list() but it returns a QuerySet where each element is a dictionary instead of a tuple.

Slicing Results

You can use Python list slicing syntax ([start:end]) to limit your QuerySet object to a certain number of results.

Example 1:

This code roughly translates to SQL as follows:

Example 2:

This code roughly translates to SQL as follows:

Example 3:

This code roughly translates to SQL as follows:

Negative slicing is not supported.

Updating Multiple Objects

Recall that one way to update an object is to call save() method after updating it’s attributes. For example:

The objects manager provides a method called update() to update one or multiple records in one step. Just like filter() method it accepts one or more keyword arguments. If the update was successful it returns the number of rows updated.

This code will update the email of author whose pk is equal to 2.

This statement is equivalent to:

Updating all objects

The above code updates the value of active field to True for all the records in the Author‘s table. The code is equivalent to the following:

The SQL equivalent of the above code is:

Deleting records

The delete() method is used to delete one or more objects. For example:

Deleting a single object.

Deleting multiple records.

You should now have a solid understanding of Django ORM. In the next lesson, we will discuss how to access data from multiple tables using Django ORM.

Note: To checkout this version of the repository type git checkout 13a.

1 thought on “Django ORM Basics

Leave a Comment