子查询中的 Django 回合
Posted
技术标签:
【中文标题】子查询中的 Django 回合【英文标题】:Django round in subquery 【发布时间】:2021-01-16 23:29:27 【问题描述】:您好,我正在使用以下代码获取带有子查询的 ListView 中每个项目的进度百分比
class projects(LoginRequiredMixin, ListView):
model = Project
template_name = 'project_list.html'
ordering = ['project_title']
paginate_by = 10
queryset = Project.objects.annotate(
todo_done=Count('todo', filter=Q(todo__state=True)) * 100 / Count('todo'),
todo_left=Count('todo', filter=Q(todo__state=False)) * 100 / Count('todo'),
)
在一个项目中,我有 12 个任务,8 个已完成,4 个正在进行中。系统返回 66% 已完成和 33% 正在进行中,总和是 99% 而不是 100%
project.todo_done
project.todo_left
栏的一部分是空白的,因为缺少 1%。我尝试按如下方式使用圆形,但这是不可能的
todo_done=round(Count('todo', filter=Q(todo__state=True)) * 100 / Count('todo')),
TypeError: type CombinedExpression doesn't define __round__ method
【问题讨论】:
【参考方案1】:您不能使用 Python 的round
,因为它不了解任何有关数据库表达式的内容。但是你可以使用Round
expression [Django-doc]:
from django.db.models import F
from django.db.models.functions import Round
queryset = Project.objects.annotate(
todo_done=Round(Count('todo', filter=Q(todo__state=True)) * 100 / Count('todo')),
todo_left=100*Count('todo') - F('todo_done'),
)
如果Todo
s中的state
只能是True
或False
,最好将todo_done
从Count('todo')
中减去100次,因为这样通常可以保证两者将总计为 100,除非当然有没有相关的Todo
s。
如果两个操作数是整数,某些数据库会使用整数除法,您可以通过将其转换为 FloatField
来防止这种情况:
from django.db.models import F, FloatField
from django.db.models.functions import Cast, Round
queryset = Project.objects.annotate(
todo_done=Round(
Cast(Count('todo', filter=Q(todo__state=True)), output_field=FloatField())
* 100 / Count('todo')
),
todo_left=100*Count('todo') - F('todo_done'),
)
【讨论】:
查询与 todo 表相关,但即使在 todo_left 中减法保证最终总和为 100,我仍然看到它没有正确舍入。 ||| todo_done=Round(Count('todo', filter=Q(todo__state=True)) * 100 / Count('todo')), todo_left=100 - Round(Count('todo', filter=Q(todo__state=True) ) * 100 / Count('todo')), 我在本地尝试过,对于 mysql,它可以工作,对于 PostgreSQL,您可能需要转换为FloatField
,否则它会进行整数除法。
@Drennos:查看使用整数除法的数据库的编辑。
你的意思是把 BooleanField 改成 FloatField?
@Drennos:不,将Todo
s 的Count(...)
转换为浮点数。以上是关于子查询中的 Django 回合的主要内容,如果未能解决你的问题,请参考以下文章
聚合子查询的 FROM 子句中的项目必须引用更高级别 FROM 子句的嵌套表