how to subquery in queryset in django?
如何在 django\\ 的查询集中创建子查询?例如,如果我有:
1 2 | select name, age from person, employee where person.id = employee.id and employee.id in (select id from employee where employee.company = 'Private') |
这就是我所做的。
1 2 | Person.objects.value('name', 'age') Employee.objects.filter(company='Private') |
但它不起作用,因为它返回两个输出...
正如 ypercube 所提到的,您的用例不需要子查询。
但无论如何,由于许多人进入此页面以学习如何进行子查询,这里是如何完成的。
1 2 | employee_query = Employee.objects.filter(company='Private').only('id').all() Person.objects.value('name', 'age').filter(id__in=employee_query) |
来源:
http://mattrobenolt.com/the-django-orm-and-subqueries/
1 2 | ids = Employee.objects.filter(company='Private').values_list('id', flat=True) Person.objects.filter(id__in=ids).values('name', 'age') |
您的问题的正确答案在这里 https://docs.djangoproject.com/en/2.1/ref/models/expressions/#subquery-expressions
例如:
1 2 3 | >>> from django.db.models import OuterRef, Subquery >>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at') >>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1])) |
您可以在 Django 中创建子查询,方法是使用未评估的查询集来过滤您的主查询集。在你的情况下,它看起来像这样:
1 2 | employee_query = Employee.objects.filter(company='Private') people = Person.objects.filter(employee__in=employee_query) |
我假设您有一个从
1 | print people.query |
正如其他人所说,您的示例并不真正需要子查询。您可以加入员工表:
1 | people2 = Person.objects.filter(employee__company='Private') |
1 2 | 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
1 2 3 4 5 6 7 8 | 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" |
有关详细信息,请参阅此文章。
如果您的子查询没有选择主键,请注意
示例:
1 2 3 4 5 6 7 8 9 10 | class Customer: pass class Order: customer: Customer pass class OrderItem: order: Order is_recalled: bool |
- 客户有订单
- 订单有订单项
现在我们正在尝试找到至少有一件被召回的订单商品的所有客户。(1)
这将无法正常工作
1 2 3 4 5 6 7 8 9 10 11 | order_ids = OrderItem.objects \\ .filter(is_recalled=True) \\ .only("order_id") customer_ids = OrderItem.objects \\ .filter(id__in=order_ids) \\ .only('customer_id') # BROKEN! BROKEN customers = Customer.objects.filter(id__in=customer_ids) |
上面的代码看起来很不错,但它产生了以下查询:
1 2 3 4 5 6 7 | select * from customer where id in ( select id -- should be customer_id from orders where id in ( select id -- should be order_id from order_items where is_recalled = true)) |
相反,应该使用
1 2 3 4 5 6 7 8 9 10 | order_ids = OrderItem.objects \\ .filter(is_recalled=True) \\ .select("order_id") customer_ids = OrderItem.objects \\ .filter(id__in=order_ids) \\ .select('customer_id') customers = Customer.objects.filter(id__in=customer_ids) |
(1) 注意:在实际情况中,我们可能会考虑\\'WHERE EXISTS\\'