Вложенные SQL запросы в Django
Вы знали, что Django ORM умеет делать вложенные SQL запросы? К своему стыду я узнал это не так давно.
Допустим, у нас есть такие модели питомника (Nursery) и питомца (Pet):
class Nursery(models.Model):
title = models.CharField(max_length=50)
class Pet(models.Model):
name = models.CharField(max_length=50)
nursery = models.ForeignKey(Nursery, related_name='pets')
Нам нужно получить всех питомцев (Pet), которые находятся в заданных питомниках (Nursery). Например в питомниках, title который начинается с “Moscow”:
nurseries = Nursery.objects.filter(title__startswith="Moscow")
Pet.objects.filter(nursery__in=nurseries)
Эти строчки сделают лишь один запрос к базе данных, в котором будет вложенный запрос :
SELECT "users_pet"."id", "users_pet"."name", "users_pet"."nursery_id" FROM "users_pet" WHERE "users_pet"."nursery_id" IN (SELECT "users_nursery"."id" FROM "users_nursery" WHERE "users_nursery"."title" LIKE Moscow%)
Однако, следует иметь в виду, что хотя выполняется один запрос к БД, это не всегда означает лучшую производительность. Тут все зависит от выбранной базы данных. Например, как советуют в документации django, в случае MySQL более эффективно выполнить два запроса вместо одного, т.к. эта БД не всегда хорошо оптимизирует вложенные запросы.
Т.е. для MySQL такой код будет эффективнее (судя по докам django):
nurseries = Nursery.objects.filter(title__startswith="Moscow").values_list('pk', flat=True)
Pet.objects.filter(nursery__in=list(nurseries))
несмотря на то, что выполнится два запроса:
SELECT "users_nursery"."id" FROM "users_nursery" WHERE "users_nursery"."title" LIKE Moscow%
SELECT "users_pet"."id", "users_pet"."name", "users_pet"."nursery_id" FROM "users_pet" WHERE "users_pet"."nursery_id" IN (1, 2)