Structure - Django ORM Working - Part 1
Tags: python, django, database
Published: 2021-06-27 07:39:59


  
Django ORM hides a lot of complexity while developing the web application. The data model declaration and querying pattern are simplified, whereas it's structured differently behind the scenes. The series of blog posts will explain Django ORM working(not just converting Python code to SQL), model declaration, querying (manager, queryset), supporting multiple drivers, writing custom queries, migrations etc...

Consider a model definition from the [Django tutorial](https://docs.djangoproject.com/en/3.2/intro/tutorial02/).

```python
from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
```



The Question and Choice model class derives from `models.Model`. Inheriting `Model` signals Django at run-time the class is a database model. `Question` model(later converted to a table) contains two extra class variables, `question_text` and `pub_date`, which will be two columns in the table. Their type is indicated by creating an instance of the respective type of fields, here `models.CharField, models.DateTimeField`. A similar work applies to the Choice model.

### Querying

Let's display all the instances of `Question` (all the rows in the table - polls_question).

```python
>>> Question.objects.all()
<QuerySet []>
```

As expected, the table is empty, and the method call returns empty result. The two things to notice are `objects.all()` and `QuerySet`. All the data entry in and out of the database through Django ORM happens through the object's interface. All the results are wrapped inside the QuerySet, even empty ones.

### From where does the `objects` instance come?

```python
>>> class Foo:
...     pass
...
>>> class Bar(Foo):
...     pass
...
>>> Bar.mro()
[<class 'Bar'>, <class 'Foo'>, <class 'object'>]
```



[Every Python class has a Method Resolution Order, which determines the behavior of the class/method invocation](https://docs.python.org/3.8/library/stdtypes.html#class.mro). In the above example, the Bar class inherits the Foo class. The `mro` method returns the order from child to patent class, Bar inherits Foo, Foo inherits object. As you can see, the Foo class has no inherited class in the code, but the `mro` method says Foo inherits object. All the Python class inherits from the object; hence `mro` method returns `object` as the last parent in the list.

```python
>>> Question.mro()
[<class 'polls.models.Question'>, 
<class 'django.db.models.base.Model'>, 
<class 'object'>]
```

MRO for `Question` is clear and returns result as expected.

```python
>>> Bar
<class 'Bar'>
>>> Question
<class 'polls.models.Question'>
>>> Question.objects
<django.db.models.manager.Manager object at 0x10bd7f1c0>
>>> Question.objects.mro()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Manager' object has no attribute 'mro'
>>> Question.objects.__class__.mro()
[<class 'django.db.models.manager.Manager'>, <class 'django.db.models.manager.BaseManagerFromQuerySet'>, <class 'django.db.models.manager.BaseManager'>, <class 'object'>]
```



The [representation](https://docs.python.org/3/reference/datamodel.html#object.__repr__) of `Question.objects` is different from the representation of `Bar` and `Question` classes. As the name indicates, `objects` is an instance of the `Manager`. The `objects`, the instance of Manager class, inherits `BaseManagerFromQuerySet` and `BaseManager`.

```python
>>> Choice
<class 'polls.models.Choice'>
>>> Choice.objects
<django.db.models.manager.Manager object at 0x10bd7f0a0>
>>> Question.objects
<django.db.models.manager.Manager object at 0x10bd7f1c0>
>>> Choice.objects is Question.objects
False
>>> Choice.objects == Question.objects
True
```

What? Even though the instance uses different id but equality test returns `True`.

````python
# It's decalared in manager class

def __eq__(self, other):
        return (
            isinstance(other, self.__class__) and
            self._constructor_args == other._constructor_args
        )
```



The logic for checking the equality has two pieces - both operands should be of the same type and their constructor args are same. In this case(behind the scenes), both the managers were called with empty arguments.

```python
>>> Question.objects._constructor_args
((), {})
>>> Choice.objects._constructor_args
((), {})
```



In the next post, I'll cover how `models.*Field` works.

### Summary

1. The Django model inherits `model.Model` and all the class variables initialized with `model.*Field` automatically behaves like a column in the table.
2. The interactions to the database happen through `ModelManager` via `objects` attribute.

### Notes:

- This post initially appeared in [my blog](https://kracekumar.com/post/structure_django_orm_working_part1/).
- Cover Photo by <a href="https://unsplash.com/@derekrliang>Derek Liang</a> on <a href="https://unsplash.com/s/photos/city-top-view>Unsplash</a>