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
相关产品推荐
相关产品推荐

