Django QuerySets and Database Shell

Django San Francisco

An object-relational mapper (ORM) makes it easy for developers to be productive by reducing the need for extensive knowledge of relational databases. ORMs can remove details from database access and replace a query with a chain of a method call, simplifying the process of working with strings of code. 

Gaining an understanding of the ORM in the Django QuerySet can strengthen your skills and help you be a better developer.

In today’s tutorial, we will create a basic example of an app with an ORM. The app will consist of models and your Django shell, and we will use it to perform queries in the QuerySet. Following along with this tutorial can help you understand the material and prepare you for a San Francisco data class or elsewhere.

Using a Django Shell

If you have experience using the Python shell, you should be able to easily use the Django shell. Keep in mind that the Django shell loads your project’s specific parameters and settings that only work in the framework, which allows you to work with your project instead of around it. It also allows you to work with the settings module inside your project. To run it, first create a new virtualenv, or virtual environment, then use this command:

python shell

Getting Started

This tutorial will use Python 3, but you can use another version if you prefer. To create the virtual environment, run the following command:

$ mkvirtualenv -p $(which python3) QuerySets
Already using interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in /home/jrb/.virtualenvs/QuerySets/bin/python3
Also creating executable in /home/jrb/.virtualenvs/QuerySets/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.

Now, we will install both IPython and Django using this command:

(QuerySets) $ pip install django ipython

To create your project, use this command:

(QuerySets) $ startproject QuerySets
(QuerySets) $ cd QuerySets/
(QuerySets) $ ./ startapp qs

Once you have installed these on your machine, you can update your QuerySets/ to add “qs” to your INSTALLED_APPS list at the end. Run this command to set up your database:

(QuerySets) jrb@caktus025:~/caktus/QuerySets$ ./ makemigrations qs
Migrations for 'qs':
    - Create model MainModel
    - Create model OnlyOne
    - Create model RelatedModel
    - Add field one to mainmodel
(QuerySets) jrb@caktus025:~/caktus/QuerySets$ ./ migrate

Now, open a new IPython session by running the Python shell. Keep track of how many queries are sent to your database by using CaptureQueriesContext to keep track of your queries. Here is the code to install the Django QuerySet manager:

class CaptureQueriesContext(object):
    def __init__(self, connection):
        self.connection = connection
    def captured_queries(self):
        return self.connection.queries[self.initial_queries:self.final_queries]
    def __enter__(self):
        self.force_debug_cursor = self.connection.force_debug_cursor
        self.connection.force_debug_cursor = True
        self.initial_queries = len(self.connection.queries_log)
        self.final_queries = None
        return self
    def __exit__(self, exc_type, exc_value, traceback):
        self.connection.force_debug_cursor = self.force_debug_cursor
        if exc_type is not None:
        self.final_queries = len(self.connection.queries_log)

By looking at the code above, you can see that this context manager references the connection to your database, known as a self.connection. A self.connection can set or unset the connection’s flag. We can still use a test suite. Test it using this code:

In [1]: from django.test.utils import CaptureQueriesContext
In [2]: from django.db import connection
In [3]: from qs import models
In [4]: with CaptureQueriesContext(connection) as context:
   ...:     print(models.MainModel.objects.all())
<QuerySet &#91;&#93;>
In [5]: print(context.initial_queries, context.final_queries)
0 1

When we run the test suite in Django QuerySet, you can tell that there are no queries in the beginning. However, the code issues a query to your database, so after the code has finished running, we end up with one.

Creating Data 

We can now add data to the Django QuerySet to explore how it works. First, populate the name fields by running the following code:

In [7]: import random
In [8]: import string
In [9]: def random_name():
   ...:     return ''.join(random.choice(string.ascii_letters) for i in range(16
   ...: ))
In [10]: random_name()
Out[10]: 'nRtybzKaSZWjHOBZ'

This code will allow us to add objects to the Django QuerySet name fields:

In [11]: with CaptureQueriesContext(connection) as context:
    ...:     models.OnlyOne.objects.bulk_create([
    ...:         models.OnlyOne(name=random_name())
    ...:         for i in range(5)
    ...:     ])
    ...:     models.MainModel.objects.bulk_create([
    ...:         models.MainModel(name=random_name(), one_id=i + 1)
    ...:         for i in range(5)
    ...:     ])
    ...:     models.RelatedModel.objects.bulk_create([
    ...:         models.RelatedModel(name=random_name(), main_id=i + 1)
    ...:         for i in range(5)
    ...:         for x in range(7)
    ...:     ])
In [12]: print(context.final_queries - context.initial_queries)

Exploring the Django QuerySet

Let’s take a look at the QuerySet to learn more about it. First, create a Django QuerySet and place it in one of your variables. Run this code to see what happens:

In [14]: with CaptureQueriesContext(connection) as context:
    ...:     qs = models.MainModel.objects.all()
In [15]: print(context.final_queries - context.initial_queries)
In [16]: print(context.captured_queries)

As you can see, a Django QuerySet was not sent to your database. Even though it has all the information needed to be populated from your database, it will not do so until the Django QuerySet requires the information. On their own, Django QuerySets will not trigger any queries.

Even if you chain a Django QuerySet from another QuerySet, Django will still not send any queries. If you wanted to send a Django QuerySet to your database, you could use a non-QuerySet-returning approach, like .count().

A Django QuerySet will go to your database whenever it needs concrete results. These types of results include implicitly or explicitly looping. Here is an example of when a concrete result is needed: 

In [20]: with CaptureQueriesContext(connection) as context:
    ...:     for m in models.MainModel.objects.all():
    ...:         obj = m
    ...:     r = repr(models.OnlyOne.objects.all())
    ...:     l = len(models.RelatedModel.objects.all())
    ...:     list_main = list(models.MainModel.objects.all())
    ...:     b = bool(models.OnlyOne.objects.all())
    ...: print(context.final_queries - context.initial_queries)
*Please note, these articles are for educational purposes and the topics covered may not be representative of the curriculum covered in our boot camp. Explore our curriculum to see what you’ll learn in our program.

Get Program Info

The following requires your attention:

Ready to learn more about Berkeley Data Analytics Boot Camp in San Francisco? Contact an admissions advisor at (510) 306-1218.