如何在Django中通过聚合与注解计算购物车商品总价?
使用Django注解与聚合计算订单总价
收到的请求JSON数据格式如下:
{ "cart":{ "pizza": 2, "burger": 3 } }
Food模型定义:
class Food(models.Model): name = models.CharField(verbose_name=_('name'), max_length=100, unique=True, blank=False, editable=True) price = models.IntegerField(verbose_name=_("maximum price"), null=False, blank=False, editable=True) discount = models.PositiveIntegerField(validators=[MaxValueValidator(100)], null=False, blank=False, default=0) created_at = models.DateTimeField(verbose_name=_("created time"), auto_now_add=True, editable=False)
现有实现通过for循环计算总价,可改用Django注解与聚合函数优化,直接在数据库层面完成计算:
from django.db.models import Sum, Case, When, IntegerField, F class OrderView(APIView): def post(self, request): srz_data = CartSerializer(data=request.data) if srz_data.is_valid(): cart_order = srz_data.data['cart'] # 构建商品名称与购买数量的匹配规则 when_clauses = [ When(name=food_name, then=quantity) for food_name, quantity in cart_order.items() ] # 注解每个商品的购买数量、小计,最后聚合总价 foods = Food.objects.filter(name__in=cart_order).annotate( quantity=Case(*when_clauses, output_field=IntegerField(), default=0) ).annotate( subtotal=F('price') * F('quantity') ) total_price = foods.aggregate(total=Sum('subtotal'))['total'] or 0
关键逻辑说明:
Case+When:根据商品名称匹配请求中的购买数量,为每个商品实例添加quantity注解字段F('price') * F('quantity'):用F表达式直接在数据库层面计算单类商品的小计,避免Python与数据库间的数据传输开销Sum('subtotal'):聚合所有商品的小计得到订单总价,or 0用于处理无匹配商品时的空值情况
内容的提问来源于stack exchange,提问作者Armin fatemi
相关产品推荐
相关产品推荐

