Django ORM 高级查询之Case-When

Python 2023-04-01

在开发中我们极有可能遇到以下情况

金额流水表 tab_money_stream
IdMoneyIsPositivepush_datetime
uuid10f2020-11-11
uuid5t2020-11-11

这个时候我们需要统计某个用户某天一共赚了多少钱,这个时候我们使用sql来完成这件事情是非常简单的,如下:

select
    sum(
        case is_positive 
            when true 
            then `money` 
            else 0 
            end)-
    sum(
        case is_positive 
            when false 
            then `money` 
            else 0 
            end) as balance
from
    tab_money_stream
where
    to_char(push_datetime, 'YYYY-MM-DD') = '2020-11-11'

但是我们使用Django ORM 来完成这个事情的时候就会又很多小伙伴抓狂了,因为在django的文档内对这一块的描述并不多,导致很多小伙伴不太明白怎么弄,接下来我们用Django 来实现一下这个sql

from django.db import connection
from django.db.models import Prefetch, Q, Sum, Case, When, F, Value, FloatField, Model

class MoneyStreamModel(Model):
    money = models.FloatField(null=True, verbose_name='金额')
    is_positive = models.BooleanField(default=True, verbose_name='增加资金')
    push_datetime = models.DateTimeField(default=timezone.now, verbose_name='发布时间')
    
    
# 主要代码
MoneyStreamModel.objects.filter(push_datetime__startswith=date).aggregate(
        balance=Sum(Case(When(is_positive=True, then=F('money')), default=Value(0.0), output_field=FloatField())) -
                          Sum(Case(When(is_positive=False, then=F('money')), default=Value(0.0),output_field=FloatField()))
        )
# 输出 {'balance':5.0}

print(connection.queries[-1]['sql'])
# SELECT (SUM(CASE WHEN "tab_money_stream"."is_positive" THEN "tab_money_stream"."money" ELSE 0.0 END) - SUM(CASE WHEN NOT "tab_money_stream"."is_positive" THEN "tab_money_stream"."money" ELSE 0.0 END)) AS "clazz_total_score" FROM "tab_money_stream" WHERE ("tab_money_stream"."push_datetime"::text LIKE '2022-03-29%')

解释一下CaseWhen在代码中如何对应于sql
# sql:
'''
case is_positive 
            when false 
            then `money` 
            else 0 
            end
'''

Case(When(is_positive=True, then=F('money')), default=Value(0.0), output_field=FloatField())
#         以他的值为条件   成立则返回then       否则返回default      以output_field类型输出
      

Case-When 可以配合聚合函数使用,以实现很多高级查询。

文章到此结束,希望对各位有所帮助,我是老四下一篇见