ORM Flashcards

1
Q

How do you find the query associated with a queryset?

A

You have a model called Event. For getting all records, you will write something like Event.objects.all(), then do str(queryset.query)

> > > queryset = Event.objects.all()
str(queryset.query)

SELECT “events_event”.”id”, “events_event”.”epic_id”,
“events_event”.”details”, “events_event”.”years_ago”
FROM “events_event”

or

> > > queryset = Event.objects.filter(years_ago__gt=5)
str(queryset.query)
SELECT “events_event”.”id”, “events_event”.”epic_id”, “events_event”.”details”,
“events_event”.”years_ago” FROM “events_event”
WHERE “events_event”.”years_ago” > 5

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

How do you use OR filter queries in Django ORM?

A

Say you want find all users with firstname starting with ‘R’ and last_name starting with ‘D’.
ORM query would look like

queryset = User.objects.filter(
        first_name\_\_startswith='R'
    ) | User.objects.filter(
    last_name\_\_startswith='D'
)
queryset
, , , , ]>
The | represents the or logical operator

Alternatively, you can use the Q objects.
qs = User.objects.filter(Q(first_name__startswith=’R’)|Q(last_name__startswith=’D’))
The Q represents the or logical operator

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

How do you use AND filter queries in Django ORM?

A

The default way to combine multiple conditions in filter is AND, so you can just do.

queryset_1 = User.objects.filter(
    first_name\_\_startswith='R',
    last_name\_\_startswith='D'
)
Alternatively, you can explicitly use the & operator on querysets.
queryset_2 = User.objects.filter(
    first_name\_\_startswith='R'
) & User.objects.filter(
    last_name\_\_startswith='D'
)
For complete customisability, you can use the Q objects.

queryset_3 = User.objects.filter(
Q(first_name__startswith=’R’) &
Q(last_name__startswith=’D’)
)

queryset_1
, , ]>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

How do you use NOT filter queries in Django ORM?

A

Method 1 using exclude

Method 2 using Q() method

> > > from django.db.models import Q
queryset = User.objects.filter(~Q(id__lt=5))
queryst
, , , , , ]>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

How to do union of two querysets from same or different models?

A

The UNION operator is used to combine the result-set of two or more querysets. The querysets can be from the same or from different models. When the querysets are from different models, the fields and their datatypes should match.

>>> q1 = User.objects.filter(id\_\_gte=5)
>>> q1
, , , , , ]>
>>> q2 = User.objects.filter(id\_\_lte=9)
>>> q2
, , , , , , , , ]>
>>> q1.union(q2)
, , , , , , , , , ]>
>>> q2.union(q1)
, , , , , , , , , ]>
The union operation can be performed only with the querysets having same fields and the datatypes. Hence our last union operation encountered error. You can do a union on two models as long as they have same fields or same subset of fields.

Since Hero and Villain both have the name and gender, we can use values_list to limit the selected fields then do a union.

Hero.objects.all().values_list(
    "name", "gender"
).union(
Villain.objects.all().values_list(
    "name", "gender"
))
This would give you all Hero and Villain objects with their name and gender.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

How to select some fields only in a queryset?

A

Django provides two ways to do this

values and values_list methods on queryset.
only_method
Say, we want to get first_name and last_name of all the users whose name starts with R. You do not want the fetch the other fields to reduce the work the DB has to do.

>>> User.objects.filter(
    first_name\_\_startswith='R'
).values('first_name', 'last_name')
> queryset = User.objects.filter(
    first_name\_\_startswith='R'
).only("first_name", "last_name")
str(queryset.query), gives us

SELECT “auth_user”.”id”, “auth_user”.”first_name”, “auth_user”.”last_name”
FROM “auth_user” WHERE “auth_user”.”first_name”::text LIKE R%
The only difference between only and values is only also fetches the id.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

How to do a subquery expression in Django?

A

Django allows using SQL subqueries. Let’s start with something simple, We have a UserParent model which has OnetoOne relation with auth user. We will find all the UserParent which have a UserParent.

> > > from django.db.models import Subquery
users = User.objects.all()
UserParent.objects.filter(user_id__in=Subquery(users.values(‘id’)))
, , ]>
Now for something more complex. For each Category, we want to find the most benevolent Hero.

The models look something like this.

class Category(models.Model):
    name = models.CharField(max_length=100)
class Hero(models.Model):
    # ...
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
benevolence_factor = models.PositiveSmallIntegerField(
    help_text="How benevolent this hero is?",
    default=50
) You can find the most benevolent Hero like this
hero_qs = Hero.objects.filter(
    category=OuterRef("pk")
).order_by("-benevolence_factor")
Category.objects.all().annotate(
    most_benevolent_hero=Subquery(
        hero_qs.values('name')[:1]
    )
)
If you look at the generated sql, you will see

SELECT “entities_category”.”id”,
“entities_category”.”name”,

(SELECT U0.”name”
FROM “entities_hero” U0
WHERE U0.”category_id” = (“entities_category”.”id”)
ORDER BY U0.”benevolence_factor” DESC
LIMIT 1) AS “most_benevolent_hero”
FROM “entities_category”
Let’s break down the queryset logic. The first part is

hero_qs = Hero.objects.filter(
category=OuterRef(“pk”)
).order_by(“-benevolence_factor”)
We are ordering the Hero object by benevolence_factor in DESC order, and using category=OuterRef(“pk”) to declare that we will be using it in a subquery.

Then we annotate with most_benevolent_hero=Subquery(hero_qs.values(‘name’)[:1]), to get use the subquery with a Category queryset. The hero_qs.values(‘name’)[:1] part picks up the first name from subquery.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

How to filter a queryset with criteria based on comparing their field values

A

Django ORM makes it easy to filter based on fixed values. To get all User objects with first_name starting with ‘R’, you can do User.objects.filter(first_name__startswith=’R’).

What if you want to compare the first_name and last name? You can use the F object. Create some users first.

In [27]: User.objects.create_user(email=”shabda@example.com”, username=”shabda”, first_name=”Shabda”, last_name=”Raaj”)
Out[27]:

In [28]: User.objects.create_user(email=”guido@example.com”, username=”Guido”, first_name=”Guido”, last_name=”Guido”)
Out[28]:
Now you can find the users where first_name==last_name

In [29]: User.objects.filter(last_name=F(“first_name”))
Out[29]: ]>
F also works with calculated field using annotate. What if we wanted users whose first and last names have same letter?

You can set the first letter from a string using Substr(“first_name”, 1, 1), so we do.

In [41]: User.objects.create_user(email=”guido@example.com”, username=”Tim”, first_name=”Tim”, last_name=”Teters”)
Out[41]:
#…
In [46]: User.objects.annotate(first=Substr(“first_name”, 1, 1), last=Substr(“last_name”, 1, 1)).filter(first=F(“last”))
Out[46]: , ]>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

How to filter FileField without any file?

A

A FileField or ImageField stores the path of the file or image. At the DB level they are same as a CharField.

So to find FileField without any file we can query as under.

no_files_objects = MyModel.objects.filter(
Q(file=’’)|Q(file=None)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

How to perform join operations in django ORM?

A

A SQL Join statement is used to combine data or rows from two or more tables based on a common field between them. Join can be carried out in many ways. Some are shown below.

> > > a1 = Article.objects.select_related(‘reporter’) // Using select_related
a1
, , , , , ]>
print(a1.query)
SELECT “events_article”.”id”, “events_article”.”headline”, “events_article”.”pub_date”, “events_article”.”reporter_id”, “events_article”.”slug”, “auth_user”.”id”, “auth_user”.”password”, “auth_user”.”last_login”, “auth_user”.”is_superuser”, “auth_user”.”username”, “auth_user”.”first_name”, “auth_user”.”last_name”, “auth_user”.”email”, “auth_user”.”is_staff”, “auth_user”.”is_active”, “auth_user”.”date_joined” FROM “events_article” INNER JOIN “auth_user” ON (“events_article”.”reporter_id” = “auth_user”.”id”) ORDER BY “events_article”.”headline” ASC
a2 = Article.objects.filter(reporter__username=’John’)
a2
, , , , ]>
print(a2.query)
SELECT “events_article”.”id”, “events_article”.”headline”, “events_article”.”pub_date”, “events_article”.”reporter_id

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

How to find second largest record using Django ORM ?

A

You would across situations when you want to find second highest user depending on their age or salary.

Though the ORM gives the flexibility of finding first(), last() item from the queryset but not nth item. You can do it using the slice operator.

We can find Nth records from the query by using slice operator.

> > > user = User.objects.order_by(‘-last_login’)[1] // Second Highest record w.r.t ‘last_login’
user.first_name
‘Raghu’
user = User.objects.order_by(‘-last_login’)[2] // Third Highest record w.r.t ‘last_login’
user.first_name
‘Sohan’
User.objects.order_by(‘-last_login’)[2] only pulls up the required object from db using LIMIT … OFFSET. If you look at the generated sql, you would see something like this.

SELECT "auth_user"."id",
       "auth_user"."password",
       "auth_user"."last_login",
       "auth_user"."is_superuser",
       "auth_user"."username",
       "auth_user"."first_name",
       "auth_user"."last_name",
       "auth_user"."email",
       "auth_user"."is_staff",
       "auth_user"."is_active",
       "auth_user"."date_joined"
FROM "auth_user"
ORDER BY "auth_user"."last_login" DESC
LIMIT 1
OFFSET 2
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Find rows which have duplicate field values

A

Say you want all users whose first_name matches another user.

You can find duplicate records using the technique below.

> > > duplicates = User.objects.values(
‘first_name’
).annotate(name_count=Count(‘first_name’)).filter(name_count__gt=1)
duplicates

If you need to fill all the records, you can do

> > > records = User.objects.filter(first_name__in=[item[‘first_name’] for item in duplicates])
print([item.id for item in records])
[2, 11, 13]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How to find distinct field values from queryset?

A

You want to find users whose names have not been repeated. You can do this like this

distinct = User.objects.values(
‘first_name’
).annotate(
name_count=Count(‘first_name’)
).filter(name_count=1)
records = User.objects.filter(first_name__in=[item[‘first_name’] for item in distinct])
This is different from User.objects.distinct(“first_name”).all(), which will pull up the first record when it encounters a distinct first_name.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

How to use Q objects for complex queries?

A

If you want to OR your conditions.

>>> from django.db.models import Q
>>> queryset = User.objects.filter(
    Q(first_name\_\_startswith='R') | Q(last_name\_\_startswith='D')
)
>>> queryset
, , , , ]>
If you want to AND your conditions.

> > > queryset = User.objects.filter(
Q(first_name__startswith=’R’) & Q(last_name__startswith=’D’)
)
queryset
, , ]>
If you want to find all users whose first_name starts with ‘R’, but not if the last_name has ‘Z’

> > > queryset = User.objects.filter(
Q(first_name__startswith=’R’) & ~Q(last_name__startswith=’Z’)
)
If you look at the generated query, you would see

SELECT "auth_user"."id",
       "auth_user"."password",
       "auth_user"."last_login",
       "auth_user"."is_superuser",
       "auth_user"."username",
       "auth_user"."first_name",
       "auth_user"."last_name",
       "auth_user"."email",
       "auth_user"."is_staff",
       "auth_user"."is_active",
       "auth_user"."date_joined"
FROM "auth_user"
WHERE ("auth_user"."first_name"::text LIKE R%
       AND NOT ("auth_user"."last_name"::text LIKE Z%))
You can combine the Q objects in more complex ways to generate complex queries.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

How to group records in Django ORM?

A

Grouping of records in Django ORM can be done using aggregation functions like Max, Min, Avg, Sum. Django queries help to create, retrieve, update and delete objects. But sometimes we need to get aggregated values from the objects. We can get them by example shown below

> > > from django.db.models import Avg, Max, Min, Sum, Count
User.objects.all().aggregate(Avg(‘id’))
{‘id__avg’: 7.571428571428571}
User.objects.all().aggregate(Max(‘id’))
{‘id__max’: 15}
User.objects.all().aggregate(Min(‘id’))
{‘id__min’: 1}
User.objects.all().aggregate(Sum(‘id’))
{‘id__sum’: 106}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

How to efficiently select a random object from a model?

A

Your category models is like this.

class Category(models.Model):
    name = models.CharField(max_length=100)
    class Meta:
        verbose_name_plural = "Categories"
    def \_\_str\_\_(self):
        return self.name
You want to get a random Category. We will look at few alternate ways to do this.

The most straightforward way, you can order_by random and fetch the first record. It would look something like this.

def get_random():
    return Category.objects.order_by("?").first()
Note: order_by('?') queries may be expensive and slow, depending on the database backend you’re using. To test other methods, we need to insert one million records in Category table. Go to your db like with python manage.py dbshell and run this.
INSERT INTO entities_category
            (name)
(SELECT Md5(Random() :: text) AS descr
 FROM   generate_series(1, 1000000));
You don’t need to understand the full details of the sql above, it creates one million numbers and md5-s them to generate the name, then inserts it in the DB.

Now, instead of sorting the whole table, you can get the max id, generate a random number in range [1, max_id], and filter that. You are assuming that there have been no deletions.

In [1]: from django.db.models import Max

In [2]: from entities.models import Category

In [3]: import random

In [4]: def get_random2():
…: max_id = Category.objects.all().aggregate(max_id=Max(“id”))[‘max_id’]
…: pk = random.randint(1, max_id)
…: return Category.objects.get(pk=pk)
…:

In [5]: get_random2()
Out[5]:

In [6]: get_random2()
Out[6]:
If your models has deletions, you can slightly modify the functions, to loop until you get a valid Category.

In [8]: def get_random3():
…: max_id = Category.objects.all().aggregate(max_id=Max(“id”))[‘max_id’]
…: while True:
…: pk = random.randint(1, max_id)
…: category = Category.objects.filter(pk=pk).first()
…: if category:
…: return category
…:

In [9]: get_random3()
Out[9]:

In [10]: get_random3()
Out[10]:
Unless your model has a lot of deletions, the while True: loop return quickly. Lets use timeit to see the differences.

In [14]: timeit.timeit(get_random3, number=100)
Out[14]: 0.20055226399563253

In [15]: timeit.timeit(get_random, number=100)
Out[15]: 56.92513192095794
get_random3 is about 283 time faster than get_random. get_random is the most generic way, but the technique in get_random3 will work unless you change changed the default way Django generates the id - autoincrementing integers, or there have been too many deletions.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

How to use arbitrary database functions in querysets?

A

Django comes with functions like Lower, Coalesce and Max, but it can’t support all database functions, expecially ones which are database specific.

Django provides Func which allows using arbitrary database functions, even if Django doesn’t provide them.

Postgres has fuzzystrmatch, which provides several functions to determine similarities. Install the extension in your postgres DB with create extension fuzzystrmatch

We will use the levenshtein function. Lets first create some Hero objects.

Hero.objects.create(name=”Zeus”, description=”A greek God”, benevolence_factor=80, category_id=12, origin_id=1)
Hero.objects.create(name=”ZeuX”, description=”A greek God”, benevolence_factor=80, category_id=12, origin_id=1)
Hero.objects.create(name=”Xeus”, description=”A greek God”, benevolence_factor=80, category_id=12, origin_id=1)
Hero.objects.create(name=”Poseidon”, description=”A greek God”, benevolence_factor=80, category_id=12, origin_id=1)
We want to find out the Hero objects which have name similar to Zeus. You can do

from django.db.models import Func, F
Hero.objects.annotate(like_zeus=Func(F('name'), function='levenshtein', template="%(function)s(%(expressions)s, 'Zeus')"))
The like_zeus=Func(F('name'), function='levenshtein', template="%(function)s(%(expressions)s, 'Zeus')") took two arguments which allowed the database representation, viz, function and template. If you need to reuse the function, you can define a class like this.
class LevenshteinLikeZeus(Func):
    function='levenshtein'
    template="%(function)s(%(expressions)s, 'Zeus')"
And then use Hero.objects.annotate(like_zeus=LevenshteinLikeZeus(F("name")))

You can then filter on this annotated field like this.

In [16]: Hero.objects.annotate(
    ...:         like_zeus=LevenshteinLikeZeus(F("name"))
    ...:     ).filter(
    ...:         like_zeus\_\_lt=2
    ...:     )
    ...:
Out[16]: , , ]>
18
Q

How to create multiple objects in one shot?

A

There are conditions when we want to save multiple objects in one go. Say we want to add multiple categories at once and we don’t want to make many queries to the database. We can use bulk_create for creating multiple objects in one shot.

Here is an example.

>>> Category.objects.all().count()
2
>>> Category.objects.bulk_create(
    [Category(name="God"),
     Category(name="Demi God"),
     Category(name="Mortal")]
)
[, , ]
>>> Category.objects.all().count()
5
bulk_create takes a list of unsaved objects.
19
Q

How to copy or clone an existing model object?

A

There is no built-in method for copying model instances, it is possible to create new instance with all fields values copied.

If an instance is saved with instance’s pk set to None, the instance is used to create a new record in the DB. That means every field other than the PK is copied.

In [2]: Hero.objects.all().count()
Out[2]: 4

In [3]: hero = Hero.objects.first()

In [4]: hero.pk = None

In [5]: hero.save()

In [6]: Hero.objects.all().count()
Out[6]: 5

20
Q

How to ensure that only one object can be created?

A

Sometimes you want to ensure that only one record can be created for a model. This is commonly required as application configuration store, or as a locking mechanism to access shared resources.

Let us convert our Origin model to be singleton.

class Origin(models.Model):
    name = models.CharField(max_length=100)
    def save(self, *args, **kwargs):
        if self.\_\_class\_\_.objects.count():
            self.pk = self.\_\_class\_\_.objects.first().pk
        super().save(*args, **kwargs)
What did we do? We overrode the save method, and set the pk to an existing value. This ensures that when create is called and any object exists, an IntegrityError is raised.
21
Q

How to update denormalized fields in other models on save?

A

You have models like this.

class Category(models.Model):
    name = models.CharField(max_length=100)
    hero_count = models.PositiveIntegerField()
    villain_count = models.PositiveIntegerField()
    class Meta:
        verbose_name_plural = "Categories"
class Hero(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    # ...
class Villain(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    # ...
You need the hero_count and villain_count, to be updated when new objects are created.

You can do something like this

class Hero(models.Model):
    # ...
def save(self, *args, **kwargs):
    if not self.pk:
        Category.objects.filter(pk=self.category_id).update(hero_count=F('hero_count')+1)
    super().save(*args, **kwargs)
class Villain(models.Model):
    # ...
def save(self, *args, **kwargs):
    if not self.pk:
        Category.objects.filter(pk=self.category_id).update(villain_count=F('villain_count')+1)
    super().save(*args, **kwargs) Note how we did not use self.category.hero_count += 1, as update will do a DB update.

The alternative method is using signals. You can do it like this.

from django.db.models.signals import pre_save
from django.dispatch import receiver

@receiver(pre_save, sender=Hero, dispatch_uid="update_hero_count")
def update_hero_count(sender, **kwargs):
    hero = kwargs['instance']
    if hero.pk:
        Category.objects.filter(pk=hero.category_id).update(hero_count=F('hero_count')+1)

@receiver(pre_save, sender=Villain, dispatch_uid=”update_villain_count”)
def update_villain_count(sender, **kwargs):
villain = kwargs[‘instance’]
if villain.pk:
Category.objects.filter(pk=villain.category_id).update(villain_count=F(‘villain_count’)+1)
4.1. Signals vs Overriding .save
Since either of signals of .save can be used for the save behviour, when should you use which one? I follow a simple rule.

If your fields depend on a model you control, override .save
If your fields depend on a model from a 3rd party app, which you do no control, use signals.

22
Q

How to perform truncate like operation using Django ORM?

A

Truncate statement in SQL is meant to empty a table for future use. Though Django doesn’t provide a builtin to truncate a table, but still similar result can be achived using delete() method. For example:

>>> Category.objects.all().count()
7
>>> Category.objects.all().delete()
(7, {'entity.Category': 7})
>>> Category.objects.all().count()
0
This works, but this uses DELETE FROM ... SQL statement. If you have a large number of records, this can be quite slow. You can add a classmethod to Category if you want to enable truncate.
class Category(models.Model):
    # ...
@classmethod
def truncate(cls):
    with connection.cursor() as cursor:
        cursor.execute('TRUNCATE TABLE "{0}" CASCADE'.format(cls._meta.db_table)) Then you can call Category.truncate() to a real database truncate.
23
Q

What signals are raised by Django during object creation or update?

A

Django provides signals which allows hooking into a model objects creation and deletion lifecycle. The signals provided by Django are

pre_init
post_init
pre_save
post_save
pre_delete
post_delete
Among these, the most commonly used signals are pre_save and post_save. We will look into them in detail.

6.1. Signals vs overriding .save
Since signals can be used for similar effects as overriding .save, which one to use is a frequent source of confusion. Here is when you should use which.

If you want other people, eg. third party apps, to override or customize the object save behaviour, you should raise your own signals
If you are hooking into the save behavior of an app you do not control, you should hook into the post_save or pre_save
If you are customizing the save behaviour of apps you control, you should override save.
Lets take an example of a UserToken model. This a class used for providing authentication and should get created whenever a User is created.
class UserToken(models.Model):
    token = models.CharField(max_length=64)
# ...
24
Q

How to convert string to datetime and store in database?

A

We can convert a date-string and store it in the database using django in many ways. Few of them are discussed below. Lets say we have a date-string as “2018-03-11” we can not directly store it to our date field, so we can use some dateparser or python library for it.

> > > user = User.objects.get(id=1)
date_str = “2018-03-11”
from django.utils.dateparse import parse_date // Way 1
temp_date = parse_date(date_str)
a1 = Article(headline=”String converted to date”, pub_date=temp_date, reporter=user)
a1.save()
a1.pub_date
datetime.date(2018, 3, 11)
from datetime import datetime // Way 2
temp_date = datetime.strptime(date_str, “%Y-%m-%d”).date()
a2 = Article(headline=”String converted to date way 2”, pub_date=temp_date, reporter=user)
a2.save()
a2.pub_date
datetime.date(2018, 3, 11)

25
Q

How to order a queryset in ascending or descending order?

A

Ordering of the queryset can be achieved by order_by method. We need to pass the field on which we need to Order (ascending/descending) the result. Query looks like this

> > > User.objects.all().order_by(‘date_joined’) # For ascending
, , , , , , , , , , , , ]>
User.objects.all().order_by(‘-date_joined’) # For descending; Not ‘-‘ sign in order_by method
, , , , , , , , , , , , ]>
You can pass multiple fields to order_by

User.objects.all().order_by(‘date_joined’, ‘-last_login’)
Looking at the SQL

SELECT "auth_user"."id",
       -- More fields
       "auth_user"."date_joined"
FROM "auth_user"
ORDER BY "auth_user"."date_joined" ASC,
         "auth_user"."last_login" DESC
26
Q

How to order a queryset in case insensitive manner?

A

Whenever we try to do order_by with some string value, the ordering happens alphabetically and w.r.t case. Like

> > > User.objects.all().order_by(‘username’).values_list(‘username’, flat=True)

If we want to order queryset in case insensitive manner, we can do like this .

.. code-block:: ipython
»> from django.db.models.functions import Lower
»> User.objects.all().order_by(Lower(‘username’)).values_list(‘username’, flat=True)

Alternatively, you can annotate with Lower and then order on annotated field.

User.objects.annotate(
uname=Lower(‘username’)
).order_by(‘uname’).values_list(‘username’, flat=True)

27
Q

How to order on two fields?

A

order_by on querysets can take one or more attribute names, allowing you to order on two or more fields.

..code-block:: ipython

In [5]: from django.contrib.auth.models import User

In [6]: User.objects.all().order_by(“is_active”, “-last_login”, “first_name”) Out[6]: , , ]>

28
Q

How to order on a field from a related model (with a foreign key)?

A

You have two models, Category and Hero.

class Category(models.Model):
    name = models.CharField(max_length=100)
class Hero(models.Model):
    # ...
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
You want to order Hero by category and inside each category by the Hero name. You can do.

Hero.objects.all().order_by(
‘category__name’, ‘name’
)
Note the double underscore(__ ) in ‘category__name’. Using the double undertscore, you can order on a field from a related model.

If you look at the SQL.

SELECT "entities_hero"."id",
       "entities_hero"."name",
       -- more fields
FROM "entities_hero"
INNER JOIN "entities_category" ON ("entities_hero"."category_id" = "entities_category"."id")
ORDER BY "entities_category"."name" ASC,
         "entities_hero"."name" ASC
29
Q

How to order on an annotated field?

A

You have two models, Category and Hero.

class Category(models.Model):
    name = models.CharField(max_length=100)
class Hero(models.Model):
    # ...
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
You want to get the Category, ordered by number of Hero in them. You can do this.
Category.objects.annotate(
    hero_count=Count("hero")
).order_by(
    "-hero_count"
)
30
Q

How to model one to one relationships?

A

One-to-one relationships occur when there is exactly one record in the first table that corresponds to one record in the related table. Here we have an example where we know that each individual can have only one Biological parents i.e., Mother and Father. We already have auth user model with us, we will add a new model UserParent as described below.

from django.contrib.auth.models import User

class UserParent(models.Model):
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        primary_key=True,
    )
    father_name = models.CharField(max_length=100)
    mother_name = models.CharField(max_length=100)

> > > u1 = User.objects.get(first_name=’Ritesh’, last_name=’Deshmukh’)
u2 = User.objects.get(first_name=’Sohan’, last_name=’Upadhyay’)
p1 = UserParent(user=u1, father_name=’Vilasrao Deshmukh’, mother_name=’Vaishali Deshmukh’)
p1.save()
p1.user.first_name
‘Ritesh’
p2 = UserParent(user=u2, father_name=’Mr R S Upadhyay’, mother_name=’Mrs S K Upadhyay’)
p2.save()
p2.user.last_name
‘Upadhyay’
The on_delete method is used to tell Django what to do with model instances that depend on the model instance you delete. (e.g. a ForeignKey relationship). The on_delete=models.CASCADE tells Django to cascade the deleting effect i.e. continue deleting the dependent models as well.

> > > u2.delete()
Will also delete the related record of UserParent.

31
Q

How to model one to many relationships?

A

In relational databases, a one-to-many relationship occurs when a parent record in one table can potentially reference several child records in another table. In a one-to-many relationship, the parent is not required to have child records; therefore, the one-to-many relationship allows zero child records, a single child record or multiple child records. To define a many-to-one relationship, use ForeignKey.:

class Article(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reporter')
    def \_\_str\_\_(self):
        return self.headline
    class Meta:
        ordering = ('headline',)

> > > u1 = User(username=’johny1’, first_name=’Johny’, last_name=’Smith’, email=’johny@example.com’)
u1.save()
u2 = User(username=’alien’, first_name=’Alien’, last_name=’Mars’, email=’alien@example.com’)
u2.save()
from datetime import date
a1 = Article(headline=”This is a test”, pub_date=date(2018, 3, 6), reporter=u1)
a1.save()
a1.reporter.id
13
a1.reporter

If you try to assign an object before saving it you will encounter a ValueError

> > > u3 = User(username=’someuser’, first_name=’Some’, last_name=’User’, email=’some@example.com’)
Article.objects.create(headline=”This is a test”, pub_date=date(2018, 3, 7), reporter=u1)
Traceback (most recent call last):

ValueError: save() prohibited to prevent data loss due to unsaved related object ‘reporter’.
Article.objects.create(headline=”This is a test”, pub_date=date(2018, 3, 7), reporter=u1)
Article.objects.filter(reporter=u1)
, ]>
The above queryset shows User u1 with multiple Articles. Hence One to Many.

32
Q

How to model many to many relationships?

A

A many-to-many relationship refers to a relationship between tables in a database when a parent row in one table contains several child rows in the second table, and vice versa.

Just to make it more interactive, we will talk about a twitter app. By just using few fields and ManyToMany field we can make a simple twitter app.

We basically have 3 basic things in Twitter, tweets, followers, favourite/unfavourite.

We have two models to make everything work. We are inheriting django’s auth_user.:

class User(AbstractUser):
    tweet = models.ManyToManyField(Tweet, blank=True)
    follower = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)
    pass
class Tweet(models.Model):
    tweet = models.TextField()
    favourite = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='user_favourite')
    def \_\_unicode\_\_(self):
        return self.tweet
What will the above model be able to do ?

1) User will able to follow/unfollow other users.
2) User will able to see tweets made by other users whom user is following.
3) User is able to favorite/unfavorite tweets.
Few operations using ManyToManyfield which can be done are:

> > > t1 = Tweet(tweet=”I am happy today”)
t1.save()
t2 = Tweet(tweet=”This is my second Tweet”)
t2.save()
u1 = User(username=’johny1’, first_name=’Johny’, last_name=’Smith’, email=’johny@example.com’)
u1.save()
u2 = User(username=’johny1’, first_name=’Johny’, last_name=’Smith’, email=’johny@example.com’)
u2.save()
u3 = User(username=’someuser’, first_name=’Some’, last_name=’User’, email=’some@example.com’)
u3.save()
We have created few tweets and few users, that didn’t involve any use of M2M field so far. Lets continue linking them in next step.

>>> u2.tweet.add(t1)
>>> u2.save()
>>> u2.tweet.add(t2)
>>> u2.save()
// User can follow other users.
>>> u2.follow.add(u1)
>>> u2.save()
// Tweets are linked to the users. Users have folloewd each other. Now we can make users do favourite/unfavourite of the tweets.
>>> t1.favourite.add(u1)
>>> t1.save()
>>> t1.favourite.add(u3)
>>> t1.save()
// For removing any users vote
>>> t1.favourite.remove(u1)
>>> t1.save()
Working example can be found in the repo: https://github.com/yashrastogi16/simpletwitter
33
Q

How to include a self-referencing ForeignKey in a model

A

Self-referencing foreign keys are used to model nested relationships or recursive relationships. They work similar to how One to Many relationships. But as the name suggests, the model references itself.

Self reference Foreignkey can be achived in two ways.

class Employee(models.Model):
    manager = models.ForeignKey('self', on_delete=models.CASCADE)

OR

class Employee(models.Model):
    manager = models.ForeignKey("app.Employee", on_delete=models.CASCADE)
34
Q

How to convert existing databases to Django models?

A

Django comes with a utility called inspectdb that can create models by introspecting an existing database. You can view the output by running this command

$ python manage.py inspectdb
Befor running this you will have to configure your database in the settings.py file. The result will be a file containing a model for each table. You may want to save that file

$ python manage.py inspectdb > models.py
The output file will be saved to your current directory. Move that file to the correct app and you have a good starting point for further customizations.

35
Q

What is the difference between null=True and blank=True?

A

The default value of both null and blank is False. Both of these values work at field level i.e., whether we want to keep a field null or blank.

null=True will set the field’s value to NULL i.e., no data. It is basically for the databases column value.

date = models.DateTimeField(null=True)
blank=True determines whether the field will be required in forms. This includes the admin and your own custom forms.

title = models.CharField(blank=True) // title can be kept blank. In the database (“”) will be stored.
null=True blank=True This means that the field is optional in all circumstances.

epic = models.ForeignKey(null=True, blank=True)
// The exception is CharFields() and TextFields(), which in Django are never saved as NULL. Blank values are stored in the DB as an empty string ('').
Also there is a special case, when you need to accept NULL values for a BooleanField, use NullBooleanField.
36
Q

How to use a UUID instead of ID as primary key?

A

Whenever we create any new model, there is an ID field attached to it. The ID field’s data type will be Integer by default.

To make id field as UUID, there is a new field type UUIDField which was added in django version 1.8+.

Example

import uuid
from django.db import models

class Event(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    details = models.TextField()
    years_ago = models.PositiveIntegerField()

> > > eventobject = Event.objects.all()
eventobject.first().id
‘3cd2b4b0c36f43488a93b3bb72029f46’

37
Q

What is the difference between a uuid vs id fields?

A

Primary key can be divided into two main parts:

Nature key
Nature keys are keys that are for free. We have a table where we want to store an object which has an attribute which is unique in the whole set of similar objects which can be stored in this table.
Surrogate key
In this case objects, we want to store in a table don’t have a unique attribute — or this unique attribute is too long.

In this blog spot, I write about a surrogate key. I believe that in bigger system nature key isn’t very convenient way to ensure uniqueness of records in a table.

What is what?
Auto increment primary keys.

The auto-increment key allows a unique number to be generated when a new record is inserted into a table. So every time we want to create a new record the database engine creates primary key automatically, and its responsibility is that this key is unique to the table.

UUID

UUID is unique too. But it is unique in “the whole universe”. It is not, of course, true. When we talk about the uniqueness of UUID we talk about “practically unique” rather than “guaranteed unique”. But for our daily purposes, this kind of uniqueness is all right.

In the following section, I described well-know disadvantages of these keys.

Obvious disadvantages of UUID.
The main disadvantage of UUID is a performance in relation databases. In the database like MSSQL, MySQL or Oracle primary keys can have some performance issues. The main problem is inserting to database. If we have clustered primary key in our database, the SQL engine has to do some reordering rows while inserting new rows. So this can be an issue if the table contains a large number of rows. This issue can be lowered by sequential guid(for example in MSSQL )
UUID can make a debugging more cumbersome — for instance, work with object with id 10 is more comfortable than with object with id 1FA169A1–1…. But for me, this is a minor disadvantage.
Storage. UUID is a four times larger than the traditional 4-byte index value. So it can have some performance and storage issues. So when you concern about storage and performance you should thoroughly decide if using UUID can harm your system.
Lack of easy ordering. The auto-increment key can be used ordering. We can easily see in what order the records were inserted.
Obvious disadvantages of auto increment keys
These types of keys aren’t suitable for distributed system. When we have a table which generated primary keys we don’t have an easy way to have this table in distributed environment.
Not so obvious advantage of UUID over auto-increment keys.
Now I would like to talk about others advantages UUID over auto increment ids. My view is an only philosophical view, but it is also vital. So hold on.

Value, first of all, we need to step aside and clarify what value is. Value has some significant traits. There is some of them:

Transparency

Let’s have a value “1”. It’s number without any other meaning, and it is not unique.

Let’s look at UUID. We have UUID like this:
“3FDBC820–1F8D-4855–9A69–9FDCFA31B7DF”.

It’s string representation of UUID. The primary benefit is that it is unique. But it isn’t the only benefit.

38
Q

How to use slug field with django for more readability?

A

Slug is a part of a URL which identifies a particular page on a website in a form readable by users. For making it work django offers us a slugfield. It can be implimented as under. We already had a model Article we will be adding slugfield to it to make it user readable.

from django.utils.text import slugify
class Article(models.Model):
    headline = models.CharField(max_length=100)
    . . .
    slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
    self.slug = slugify(self.headline)
    super(Article, self).save(*args, **kwargs)
. . .

> > > u1 = User.objects.get(id=1)
from datetime import date
a1 = Article.objects.create(headline=”todays market report”, pub_date=date(2018, 3, 6), reporter=u1)
a1.save()
// slug here is auto-generated, we haven’t created it in the above create method.
a1.slug
‘todays-market-report’
Slug is useful because:
it’s human friendly (eg. /blog/ instead of /1/).
it’s good SEO to create consistency in title, heading and URL.

39
Q

How to add multiple databases to the django application ?

A

The configuration of database related stuff is mostly done in settings.py file. So to add multiple database to our django project we need add them in DATABASES dictionary.

DATABASE_ROUTERS = [‘path.to.DemoRouter’]
DATABASE_APPS_MAPPING = {‘user_data’: ‘users_db’,
‘customer_data’:’customers_db’}

DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.sqlite3’,
‘NAME’: os.path.join(BASE_DIR, ‘db.sqlite3’),
},
‘users_db’: {
‘NAME’: ‘user_data’,
‘ENGINE’: ‘django.db.backends.postgresql’,
‘USER’: ‘postgres_user’,
‘PASSWORD’: ‘password’
},
‘customers_db’: {
‘NAME’: ‘customer_data’,
‘ENGINE’: ‘django.db.backends.mysql’,
‘USER’: ‘mysql_cust’,
‘PASSWORD’: ‘root’
}
}
With multiple databases it will be good to talk about Database Router. The default routing scheme ensures that if a database isn’t specified, all queries fall back to the default database. Database Router defaults to [].

class DemoRouter:
“””
A router to control all database operations on models in the
user application.
“””
def db_for_read(self, model, **hints):
“””
Attempts to read user models go to users_db.
“””
if model._meta.app_label == ‘user_data’:
return ‘users_db’
return None

def db_for_write(self, model, **hints):
    """
    Attempts to write user models go to users_db.
    """
    if model._meta.app_label == 'user_data':
        return 'users_db'
    return None

def allow_relation(self, obj1, obj2, **hints):
    """
    Allow relations if a model in the user app is involved.
    """
    if obj1._meta.app_label == 'user_data' or \
       obj2._meta.app_label == 'user_data':
       return True
    return None
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth app only appears in the 'users_db'
        database.
        """
        if app_label == 'user_data':
            return db == 'users_db'
        return None
Respective models would be modified as
class User(models.Model):
    username = models.Charfield(ax_length=100)
    . . .
        class Meta:
        app_label = 'user_data'

class Customer(models.Model):
name = models.TextField(max_length=100)
. . .
class Meta:
app_label = ‘customer_data’
Few helpful commands while working with multiple databases.

$ ./manage.py migrate –database=users_db

40
Q

How to assert that a function used a fixed number of queries?

A

We can count number of queries for testing by using assertNumQueries() method.

def test_number_of_queries(self):
    User.objects.create(username='testuser1', first_name='Test', last_name='user1')
    # Above ORM create will run only one query.
    self.assertNumQueries(1)
    User.objects.filter(username='testuser').update(username='test1user')
    # One more query added.
    self.assertNumQueries(2)
41
Q

How to speed tests by reusing database between test runs?

A

When we execute the command python manage.py test, a new db is created everytime. This doesn’t matter much if we don’t have many migrations.

But when we have many migrations, it takes a long time to recreate the database between the test runs. To avoid such situations, we may reuse the old database.

You can prevent the test databases from being destroyed by adding the –keepdb flag to the test command. This will preserve the test database between runs. If the database does not exist, it will first be created. If any migrations have been added since the last test run, they will be applied in order to keep it up to date.

$ python manage.py test –keepdb

42
Q

How to reload a model object from the database?

A

Models can be reloaded from the databse using refresh_from_db() method. THis proves helpful during testing. For example.

class TestORM(TestCase):
    def test_update_result(self):
        userobject = User.objects.create(username='testuser', first_name='Test', last_name='user')
        User.objects.filter(username='testuser').update(username='test1user')
        # At this point userobject.val is still testuser, but the value in the database
        # was updated to test1user. The object's updated value needs to be reloaded
        # from the database.
        userobject.refresh_from_db()
        self.assertEqual(userobject.username, 'test1user')