【问题标题】:Django round in subquery子查询中的 Django 回合
【发布时间】: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

【问题讨论】:

    标签: django orm subquery


    【解决方案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'),
    )

    如果Todos中的state只能是TrueFalse,最好将todo_doneCount('todo')中减去100次,因为这样通常可以保证两者将总计为 100,除非当然有没有相关的Todos。

    如果两个操作数是整数,某些数据库会使用整数除法,您可以通过将其转换为 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:不,将Todos 的Count(...) 转换为浮点数。
    猜你喜欢
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 2018-12-04
    • 2017-07-01
    • 2017-07-21
    • 2011-08-30
    • 1970-01-01
    • 2020-11-26
    相关资源
    最近更新 更多