如果未找到行,则Django Coalesce返回null

时间:2019-12-10 11:08:51

标签: django

我正在使用Coalesce function来阻止汇总Sum返回None

Coalesce(Sum('ext_price'), 0)

问题在于,如果未找到任何行,它仍将返回null。有没有办法修改该函数,以便在找不到行的情况下返回零?

class Coalesce(Func):
    """Return, from left to right, the first non-null expression."""
    function = 'COALESCE'

    def __init__(self, *expressions, **extra):
        if len(expressions) < 2:
            raise ValueError('Coalesce must take at least two expressions')
        super().__init__(*expressions, **extra)

我的意思是没有行

queryset = MyModel.objects.none()
total = queryset.aggregate(total=Coalesce(Sum('total'), Value(0)).get('total')
total == None  # True

2 个答案:

答案 0 :(得分:2)

您需要将值包装在Value对象中

from django.db.models import Coalesce, Value

Coalesce(Sum('ext_price'), Value(0))

您可以实现自己的Coalesce函数,例如:

from django.db.models import Value
from django.db.models.functions import Coalesce

class CoalesceZero(Coalesce):

    def __init__(self, *expressions, **extra):
        super().__init__(*expressions, Value(0), **extra)

在这种情况下,您可以使用CoalesceZero,而不再需要将Value(0)写为最后一个值。

编辑:如果您进行了汇总,则此COALESCE当然不会被评估。然后,您可以在Python代码中使用简单的or 0

queryset = MyModel.objects.none()
total = queryset.aggregate(total=Sum('total')).get('total') or 0

答案 1 :(得分:0)

如果您只有几次,Willem上面关于聚合的答案是很棒的;如果您必须在很多地方这样做,可以执行以下操作:

class AggregateCoalesceMixin:
    @staticmethod
    def aggregate_coalesce(
        aggregate: Dict[str, Any],
        default_from_value: Optional[Any] = None,
        default_to_value: Optional[Any] = 0,
        default_map: Optional[Dict[str, Tuple[Any, Any]]] = None,
    ) -> Dict[str, Any]:
        for k, v in aggregate.items():
            if default_map and k in default_map:
                if v == default_map[k][0]:
                    aggregate[k] = default_map[k][1]
                    continue
            elif v == default_from_value:
                aggregate[k] = default_to_value
        return aggregate

您可以这样使用:

aggregate_result = {"item_1": None, "item_2": 20}
aggregate_result = self.aggregate_coalesce(aggregate_result)
>> {"item_1": 0, "item_2": 20}

如果需要更多控制,可以提供一个合并值图:

aggregate_result = {"item_1": None, "item_2": '', "item_3": 20}
map = {"item_1": (None, 0), "item_2": ('', 'NA'), "item_3": (None, 0)}
aggregate_result = self.aggregate_coalesce(aggregate_result, default_map=map)
>> {"item_1": 0, "item_2": 'NA', "item_3": 20}