Django 从注释计数中排除
Django exclude from annotation count
我有以下申请:
from django.db import models
class Worker(models.Model):
name = models.CharField(max_length=60)
def __str__(self):
return self.name
class Job(models.Model):
worker = models.ForeignKey(Worker)
is_completed = models.BooleanField()
我想用已完成作业的计数来注释 Workers 查询。
我将尝试使用以下脚本来完成:
from myapp.models import Worker, Job
from django.db.models import Count
w = Worker.objects.create(name='Worker1')
Job.objects.create(worker=w, is_completed=False)
Job.objects.create(worker=w, is_completed=False)
Job.objects.create(worker=w, is_completed=True)
Job.objects.create(worker=w, is_completed=True)
workers = Worker.objects.all().annotate(num_jobs=Count('job'))
workers[0].num_jobs
# >>> 4
workers = Worker.objects.all().exclude(job__is_completed=False).annotate(num_jobs=Count('job'))
# >>> []
上次查询结果为空。如何从反向关系中排除元素?
Django 1.8,python2.7
UPD. 我希望查询集中的所有工作人员,即使是那些工作为零的工作人员
更新:好吧,我用这个来生成解决方案,我想我用 Conditional Expressions:
得到了它
Conditional expressions let you use if ... elif ... else logic within
filters, annotations, aggregations, and updates. A conditional
expression evaluates a series of conditions for each row of a table
and returns the matching result expression.
注意:Conditional Expressions(例如Case
和When
)是Django 1.8[=25]中的新增功能=],正如@Pynchia
所指出的
from django.db.models import IntegerField, Sum, Case, When
workers = Worker.objects.annotate(
num_jobs=Sum(
Case(
When(job__is_completed=True, then=1),
default=0,
output_field=IntegerField()
)
)
)
现在,每个工人都会有一个 num_jobs,它将是一个整数,显示该工人完成了多少工作:)
以下
workers = Worker.objects.filter(job__is_completed=True)).annotate(num_jobs=Count('job__is_completed'))
标注那些至少完成了一项工作的工人。
结果查询集中不包括那些完成了零个作业的作业。
如果您希望所有工作人员都出现在结果查询集中,那么我们可以这样写
workers = Worker.objects.annotate(num_jobs=CountIf('job__is_completed', job__is_completed=True))
但不幸的是,我们不能。
所以我在这里超出了我的深度,我相信我的回答是部分的。
我欢迎比我更有能力的人的介入,他可以阐明这件事。
参考这个Django proposed feature(关闭)
和this SO QA
更新: Django 1.8 引入了条件表达式。 @BogdiG 的回答使用此类新运算符来解决问题。荣誉!
更新
如果你想计算每个工人完成的工作,我们可以通过 .extra()
:
使用子查询
Worker.objects.extra(select={'jobs_done':
'SELECT COUNT(*) FROM {job_tbl} WHERE worker_id = {worker_tbl}.id AND is_completed'
.format(worker_tbl=Worker._meta.db_table, job_tbl=Job._meta.db_table)})
Django 现在支持 .
中描述的语法中条件表达式 SUM(CASE WHEN is_completed = True THEN 1 ELSE 0 END)
的 Python 映射真是太好了
删除了关于 filter/exclude
的内容
这里有2个选项。第一个是直接 Q
过滤器 Count
:
from myapp.models import Worker
from django.db.models import Count, Q
workers = Worker.objects.annotate(
completed_jobs_count=Count("job", filter=Q(job__is_completed=True))
)
第二个是在 Count
上排除 Q
过滤器(有时需要它,因为 Count
没有直接的 exclude
选项):
from myapp.models import Worker
from django.db.models import Count, Q
workers = Worker.objects.annotate(
completed_jobs_count=Count("job", filter=~Q(job__is_completed=False))
)
我有以下申请:
from django.db import models
class Worker(models.Model):
name = models.CharField(max_length=60)
def __str__(self):
return self.name
class Job(models.Model):
worker = models.ForeignKey(Worker)
is_completed = models.BooleanField()
我想用已完成作业的计数来注释 Workers 查询。
我将尝试使用以下脚本来完成:
from myapp.models import Worker, Job
from django.db.models import Count
w = Worker.objects.create(name='Worker1')
Job.objects.create(worker=w, is_completed=False)
Job.objects.create(worker=w, is_completed=False)
Job.objects.create(worker=w, is_completed=True)
Job.objects.create(worker=w, is_completed=True)
workers = Worker.objects.all().annotate(num_jobs=Count('job'))
workers[0].num_jobs
# >>> 4
workers = Worker.objects.all().exclude(job__is_completed=False).annotate(num_jobs=Count('job'))
# >>> []
上次查询结果为空。如何从反向关系中排除元素?
Django 1.8,python2.7
UPD. 我希望查询集中的所有工作人员,即使是那些工作为零的工作人员
更新:好吧,我用这个来生成解决方案,我想我用 Conditional Expressions:
得到了它Conditional expressions let you use if ... elif ... else logic within filters, annotations, aggregations, and updates. A conditional expression evaluates a series of conditions for each row of a table and returns the matching result expression.
注意:Conditional Expressions(例如Case
和When
)是Django 1.8[=25]中的新增功能=],正如@Pynchia
from django.db.models import IntegerField, Sum, Case, When
workers = Worker.objects.annotate(
num_jobs=Sum(
Case(
When(job__is_completed=True, then=1),
default=0,
output_field=IntegerField()
)
)
)
现在,每个工人都会有一个 num_jobs,它将是一个整数,显示该工人完成了多少工作:)
以下
workers = Worker.objects.filter(job__is_completed=True)).annotate(num_jobs=Count('job__is_completed'))
标注那些至少完成了一项工作的工人。 结果查询集中不包括那些完成了零个作业的作业。
如果您希望所有工作人员都出现在结果查询集中,那么我们可以这样写
workers = Worker.objects.annotate(num_jobs=CountIf('job__is_completed', job__is_completed=True))
但不幸的是,我们不能。 所以我在这里超出了我的深度,我相信我的回答是部分的。 我欢迎比我更有能力的人的介入,他可以阐明这件事。
参考这个Django proposed feature(关闭)
和this SO QA
更新: Django 1.8 引入了条件表达式。 @BogdiG 的回答使用此类新运算符来解决问题。荣誉!
更新
如果你想计算每个工人完成的工作,我们可以通过 .extra()
:
Worker.objects.extra(select={'jobs_done':
'SELECT COUNT(*) FROM {job_tbl} WHERE worker_id = {worker_tbl}.id AND is_completed'
.format(worker_tbl=Worker._meta.db_table, job_tbl=Job._meta.db_table)})
Django 现在支持
SUM(CASE WHEN is_completed = True THEN 1 ELSE 0 END)
的 Python 映射真是太好了
删除了关于 filter/exclude
这里有2个选项。第一个是直接 Q
过滤器 Count
:
from myapp.models import Worker
from django.db.models import Count, Q
workers = Worker.objects.annotate(
completed_jobs_count=Count("job", filter=Q(job__is_completed=True))
)
第二个是在 Count
上排除 Q
过滤器(有时需要它,因为 Count
没有直接的 exclude
选项):
from myapp.models import Worker
from django.db.models import Count, Q
workers = Worker.objects.annotate(
completed_jobs_count=Count("job", filter=~Q(job__is_completed=False))
)