这是一个前沿的功能,我目前正在解决这个问题并迅速流血.我想在现有的查询集上注释子查询聚合.在1.11之前执行此操作要么意味着自定义SQL,要么锤击数据库.这是这方面的文档,以及它的示例:
from django.db.models import OuterRef, Subquery, Sum
comments = Comment.objects.filter(post=OuterRef('pk')).values('post')
total_comments = comments.annotate(total=Sum('length')).values('total')
Post.objects.filter(length__gt=Subquery(total_comments))
Run Code Online (Sandbox Code Playgroud)
他们在总体上注释,这对我来说似乎很奇怪,但无论如何.
我正在努力解决这个问题,所以我正在把它煮回来,回到我有数据的最简单的现实世界的例子.我有Carparks包含很多Spaces.使用,Book?Author如果这让你更快乐,但是 - 现在 - 我只想使用Subquery*来注释相关模型的计数.
spaces = Space.objects.filter(carpark=OuterRef('pk')).values('carpark')
count_spaces = spaces.annotate(c=Count('*')).values('c')
Carpark.objects.annotate(space_count=Subquery(count_spaces))
Run Code Online (Sandbox Code Playgroud)
这给了我一个可爱的ProgrammingError: more than one row returned by a subquery used as an expression,在我的脑海里,这个错误非常有意义.子查询返回带有注释总计的空格列表.
这个例子表明会发生某种魔法,我最终会得到一个我可以使用的数字.但这不是在这里发生的?如何对聚合子查询数据进行注释?
我建造了一个新的停车场/太空模型,它起作用了.所以下一步是弄清楚我的SQL中毒了什么.根据Laurent的建议,我看了一下SQL并尝试使它更像是他们在答案中发布的版本.这就是我发现真正问题的地方:
SELECT "bookings_carpark".*, (SELECT COUNT(U0."id") AS "c"
FROM "bookings_space" U0
WHERE U0."carpark_id" = ("bookings_carpark"."id")
GROUP BY U0."carpark_id", U0."space"
)
AS "space_count" FROM "bookings_carpark"; …Run Code Online (Sandbox Code Playgroud) 请帮助我,我已经被困在这个问题上太久了:(
我有这两个模型:
class Specialization(models.Model):
name = models.CharField("name", max_length=64)
class Doctor(models.Model):
name = models.CharField("name", max_length=128)
# ...
specialization = models.ForeignKey(Specialization)
Run Code Online (Sandbox Code Playgroud)
我想用具有该专业的医生数量来注释查询集中的所有专业。
我经历了一个循环并做了一个简单的: Doctor.objects.filter(specialization=spec).count()然而事实证明这太慢而且效率低下。我读得越多,就越意识到使用此处SubQuery来筛选专业化的医生是有意义的OuterRef。这就是我想出的:
doctors = Doctor.objects.all().filter(specialization=OuterRef("id")) \
.values("specialization_id") \
.order_by()
add_doctors_count = doctors.annotate(cnt=Count("specialization_id")).values("cnt")[:1]
spec_qs_with_counts = Specialization.objects.all().annotate(
num_applicable_doctors=Subquery(add_doctors_count, output_field=IntegerField())
)
Run Code Online (Sandbox Code Playgroud)
对于每个专业,我得到的输出仅为 1。代码只是用它来注释每个医生对象specialization_id,然后注释该组内的计数,这意味着它将是 1。
不幸的是,这对我来说并不完全有意义。在我最初的尝试中,我使用了一个聚合来进行计数,虽然它可以单独工作,但它不能作为 a 工作SubQuery,但我收到此错误:
This queryset contains a reference to an outer query and may only be used in a subquery.
我之前发布过这个问题,有人建议这样做Specialization.objects.annotate(count=Count("doctor"))
然而,这不起作用,因为我需要计算特定的医生查询集。
但是,我没有得到相同的结果:
python django django-aggregation django-annotate django-subquery
我OuterRef在Django 1.11子查询中使用annotate()时遇到问题.示例模型:
class A(models.Model):
name = models.CharField(max_length=50)
class B(models.Model):
a = models.ForeignKey(A)
Run Code Online (Sandbox Code Playgroud)
现在是一个带有子查询的查询(这没有任何意义,但说明了我的问题):
A.objects.all().annotate(
s=Subquery(
B.objects.all().annotate(
n=OuterRef('name')
).values('n')[:1],
output_field=CharField()
)
)
Run Code Online (Sandbox Code Playgroud)
这会出现以下错误:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "myapp/models.py", line 25, in a
n=OuterRef('name')
File ".virtualenv/lib/python2.7/site-packages/django/db/models/query.py", line 948, in annotate
if alias in annotations and annotation.contains_aggregate:
AttributeError: 'ResolvedOuterRef' object has no attribute 'contains_aggregate'
Run Code Online (Sandbox Code Playgroud)
是否无法基于OuterRef注释子查询?
找到一个解决方法,这将允许我现在继续前进,但它并不好.
class RawCol(Expression):
def __init__(self, model, field_name, output_field=None):
field = model._meta.get_field(field_name)
self.table = model._meta.db_table
self.column = field.column …Run Code Online (Sandbox Code Playgroud) 我最近升级到 django 1.11,我想使用新发布的Subquery exrpession功能。有以下两种型号
class Project(models.Model):
title = models.CharField(_("Project Name"), max_length=128)
class PrivateDonation(models.Model):
project = models.ForeignKey(Project)
value = models.DecimalField(_("value"),max_digits=19, decimal_places=2)
............
Run Code Online (Sandbox Code Playgroud)
我想获得一个用每个项目的私人捐赠价值总和注释的 Project 对象的查询集。我知道,还有其他方法可以实现这一点,而且我的应用程序已经有了一个可行的解决方案,但由于我正在学习此功能,因此我尝试了以下查询
private_donations = PrivateDonation.objects.filter(project=OuterRef('pk')).values('value')
private_donations_sum = private_donations.annotate(s=Sum('value')).values('s')
Project.objects.annotate(pd_sum=Subquery(queryset=private_donations_sum))
Run Code Online (Sandbox Code Playgroud)
但是上面的查询抛出异常
django.db.utils.ProgrammingError: more than one row returned by a subquery used as an expression
Run Code Online (Sandbox Code Playgroud)
唯一成功运行的查询是下面的查询。
private_donations = PrivateDonation.objects.filter(project=OuterRef('pk')).order_by().values('project')
private_donations_count = private_donations.annotate(c=Count('*')).values('c')
projects = Project.objects.annotate(space_count=Subquery(queryset=private_donations_count))
Run Code Online (Sandbox Code Playgroud)
但是,如果我在“private_donations”查询中选择“project”属性以外的任何其他内容,则会引发相同的错误
这是堆栈跟踪
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<input>", line 1, in …Run Code Online (Sandbox Code Playgroud) 我的模型结构的简化示例是
class Corporation(models.Model):
...
class Division(models.Model):
corporation = models.ForeignKey(Corporation)
class Department(models.Model):
division = models.ForeignKey(Division)
type = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)
现在我想显示一个表格,显示公司,其中列将包含某种类型的部门数量,例如type=10.目前,这是通过Corporation模型上的帮助程序实现的,例如,检索那些帮助程序
class Corporation(models.Model):
...
def get_departments_type_10(self):
return (
Department.objects
.filter(division__corporation=self, type=10)
.count()
)
Run Code Online (Sandbox Code Playgroud)
这里的问题是,由于N + 1问题,这绝对是谋杀性能.
我试图用接近这个问题select_related,prefetch_related,annotate,和subquery,但我没有带能够得到我需要的结果.
理想情况下,查询Corporation集中的每个应该使用一个整数进行注释,该整数type_10_count反映了该类型的部门数量.
我确信我可以用原始sql做一些事情.extra(),但是文档宣布它将被弃用(我在Django 1.11上)
编辑:原始sql解决方案的示例
corps = Corporation.objects.raw("""
SELECT
*,
(
SELECT COUNT(*)
FROM foo_division div ON div.corporation_id = c.id
JOIN foo_department dept ON dept.division_id = div.id
WHERE dept.type …Run Code Online (Sandbox Code Playgroud) 我有一个公司和用户模型以及相关模型 CompanyRecruiter:
class CompanyRecruiter(models.Model):
organization = models.ForeignKey(Company, related_name="company_recruiters")
recruiter = models.ForeignKey(User, related_name="company_recruiters")
Run Code Online (Sandbox Code Playgroud)
我想注释作为招聘人员的用户的用户 ID 列表,以便公司稍后能够对其进行过滤:
Company.objects.annotate(some_stuff=some_other_stuff).values_list("user_ids", flat=True)
# [ [1, 2], [1, 56], [] ]
Run Code Online (Sandbox Code Playgroud)
我已经尝试使用自定义聚合和子查询但没有成功。我用的是postgres。
我在我的项目中使用了 postgresql 数据库,我使用了 django文档中的以下示例。
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]))
Run Code Online (Sandbox Code Playgroud)
但不是最新的评论者电子邮件,我需要最后两封评论者的电子邮件。我改变了[:1]对[:2],但此异常引发:ProgrammingError: more than one row returned by a subquery used as an expression。
django django-orm django-postgresql django-annotate django-subquery