7. 如何在Django中使用子查询(内连接)?¶
Django 允许使用SQL子查询,我们有一个 UserParent
模型,其中和auth user有一对一的关系。我们要找到所有具有 UserParent
字段的 UserParent
。
>>> from django.db.models import Subquery
>>> users = User.objects.all()
>>> UserParent.objects.filter(user_id__in=Subquery(users.values('id')))
<QuerySet [<UserParent: UserParent object (2)>, <UserParent: UserParent object (5)>, <UserParent: UserParent object (8)>]>
现在换点更复杂的,我们想要在每一个 Category
找到最勇敢的 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)
benevolence_factor = models.PositiveSmallIntegerField(
help_text="How benevolent this hero is?",
default=50
)
你用以下方式找到最勇敢的英雄:
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]
)
)
如果你查看生成的sql,你会看到:
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"
我们来分解下请求集的逻辑。第一步是:
hero_qs = Hero.objects.filter(
category=OuterRef("pk")
).order_by("-benevolence_factor")
我们正在给 Hero
以倒序方式排序,并且使用 category=OuterRef("pk")
来声明我们会在子查询中用到它。
然后我们使用 most_benevolent_hero=Subquery(hero_qs.values('name')[:1])
以获得 Category
查询集的子查询。 hero_qs.values('name')[:1]
选取了子查询中的一个名称。