You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django对子模型字段执行aggregate Sum计算以更新父模型库存字段

Django 子模型聚合求和更新父模型库存字段实现方案

原代码存在的问题

  • Supply模型的bottles_number字段定义语法错误,缺少闭合括号
  • aggregate方法中指定的聚合结果别名是total,但后续取值时用了不存在的键bottles_used__sum,且键名没有加引号
  • 没有处理无领用记录时Sum返回None的情况,直接做减法会触发类型错误
  • 仅在Supply的save方法中更新库存,新增/修改/删除领用记录(Pick)时不会自动同步更新Supply的剩余库存

修正后完整代码

from django.db import models
from django.db.models import Sum
from decimal import Decimal

class Supply(models.Model):
    """库存批次入库记录"""
    # 补全字段定义的闭合括号
    bottles_number = models.PositiveSmallIntegerField()
    bottles_remaining = models.DecimalField(max_digits=4, decimal_places=1, default=0.0)

    def calculate_remaining(self):
        # 聚合求和,default参数处理无领用记录时返回0,避免空值运算报错
        used_total = Pick.objects.filter(supply=self).aggregate(
            total=Sum('n_bottles', default=0)
        )['total']
        # 统一数值类型避免运算错误
        return Decimal(self.bottles_number) - used_total

    def save(self, *args, **kwargs):
        self.bottles_remaining = self.calculate_remaining()
        super().save(*args, **kwargs)

class Pick(models.Model):
    """库存批次领用记录"""
    supply = models.ForeignKey(Supply, on_delete = models.CASCADE)
    n_bottles = models.DecimalField(max_digits=4, decimal_places=1)

    # 重写save方法,新增/修改领用记录后自动更新对应批次库存
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        self.supply.save()

    # 重写delete方法,删除领用记录后自动更新对应批次库存
    def delete(self, *args, **kwargs):
        related_supply = self.supply
        super().delete(*args, **kwargs)
        related_supply.save()

注意事项

  • 如果使用bulk_create、bulk_update、批量删除等Django批量操作接口,不会触发单个实例的save/delete方法,需要在批量操作完成后手动调用关联Supply实例的save方法更新库存
  • 若使用的Django版本低于3.2,不支持Sum的default参数,可以将聚合取值逻辑改为:
    used_total = Pick.objects.filter(supply=self).aggregate(total=Sum('n_bottles'))['total'] or 0
    

内容的提问来源于stack exchange,提问作者Flavio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 09:21:03