我正在使用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
答案 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}