如何在Django中对JSONField内指定SKU的商品价格求和?
解决Django中JSONField嵌套商品价格求和问题
方法一:Python层面求和(简单直观,适合小数据量)
既然已经筛选出目标订单,直接遍历每个订单的商品列表,判断SKU后累加价格即可:
total_earned = 0 for order in orders: for product in order.products: if product['sku'] == '002-2-1': total_earned += float(product['price']) print(total_earned) # 输出总金额
方法二:数据库层面聚合(高效,适合大数据量)
如果订单数据量较大,推荐直接在数据库层面完成计算,避免把所有数据加载到内存。以PostgreSQL为例(Django的JSONField在PostgreSQL底层是jsonb类型),可以通过展开JSON数组、过滤SKU后求和:
方式1:使用RawSQL
直接编写SQL语句实现:
total_earned = Order.objects.raw(""" SELECT SUM((item->>'price')::numeric) AS total FROM orders_order, jsonb_array_elements(products::jsonb) AS item WHERE item->>'sku' = '002-2-1' """)[0].total
方式2:使用Django ORM函数封装
通过自定义Func调用PostgreSQL的jsonb函数,保持ORM风格:
from django.db.models import Func, FloatField, Sum, Subquery, OuterRef, CharField # 自定义函数:展开JSON数组为行 class JsonbArrayElements(Func): function = 'jsonb_array_elements' template = "%(function)s(%(expressions)s::jsonb)" # 子查询:计算单个订单中符合条件的商品总价 order_item_sums = Order.objects.filter( id=OuterRef('id') ).annotate( # 提取每个商品的sku和price item_sku=Func( JsonbArrayElements('products'), function='->>', template="%(function)s(%(expressions)s, 'sku')", output_field=CharField() ), item_price=Func( JsonbArrayElements('products'), function='->>', template="%(function)s(%(expressions)s, 'price')", output_field=FloatField() ) ).filter(item_sku="002-2-1").annotate( order_total=Sum('item_price') ).values('order_total') # 聚合所有订单的总价 total_earned = Order.objects.filter( products__contains=[{"sku": "002-2-1"}] ).annotate( order_sum=Subquery(order_item_sums[:1]) ).aggregate(total=Sum('order_sum'))['total']
原有代码无法运行的原因
你尝试的products__contains=[{"price"}]写法不符合Django ORM规则:
contains是用于筛选的查询条件,不能直接嵌套在Sum函数中- JSON数组的嵌套元素无法通过常规字段路径(如
products__price)直接访问,必须先将数组展开为行数据才能进行聚合计算
内容的提问来源于stack exchange,提问作者Iren E
相关产品推荐
相关产品推荐

