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

如何在Django中实现跨表IntegerField数值扣减(花束场景)

需求说明

工作机制

向Bouquet表添加产品时,在CompositionOfTheBouquetInline类中可从Flower表选择花卉对象并指定数量。

示例

  • Flower表中存在“Rose”,stock = 10
  • Bouquet表中创建“Bouquet of roses”花束,stock = 1
  • 在CompositionOfTheBouquet表中选择5朵“Rose”并保存

预期结果

  • Flower表中“Rose”的stock 变为5

计算公式

  • Flower.stock = Flower.stock - (CompositionOfTheBouquet.count * Bouquet.stock)

现有代码

models.py

class Flower(models.Model):
    title = models.CharField(max_length=100)
    stock = models.PositiveIntegerField(default=0)

class Bouquet(models.Model):
    title = models.CharField(max_length=150)
    stock = models.PositiveIntegerField(default=0)

class CompositionOfTheBouquet(models.Model):
    flower = models.ForeignKey(
        Flower, on_delete=models.PROTECT
    )
    bouquet = models.ForeignKey(
        Bouquet, on_delete=models.PROTECT
    )
    count = models.PositiveIntegerField(default=0)

admin.py

from .models import Flower, Bouquet, CompositionOfTheBouquet


class CompositionOfTheBouquetInline(admin.TabularInline):
    model = CompositionOfTheBouquet

@admin.register(Flower)
class Flower(admin.ModelAdmin):
    pass

@admin.register(Bouquet)
class Bouquet(admin.ModelAdmin):
    inlines = [CompositionOfTheBouquetInline, ]

核心需求

通过admin面板添加Bouquet时,需按照公式自动扣减对应花卉的stock字段值并保存到Flower表。


实现方案

要搞定这个自动扣减库存的需求,我们可以重写Bouquet对应的ModelAdmin中的save_related方法——这个方法会在保存花束主对象及其关联的花卉组成条目之后触发,刚好适合处理关联的库存更新逻辑。

修改后的admin.py代码如下:

from django.contrib import admin
from django.db.models import F
from .models import Flower, Bouquet, CompositionOfTheBouquet


class CompositionOfTheBouquetInline(admin.TabularInline):
    model = CompositionOfTheBouquet

@admin.register(Flower)
class FlowerAdmin(admin.ModelAdmin):
    pass

@admin.register(Bouquet)
class BouquetAdmin(admin.ModelAdmin):
    inlines = [CompositionOfTheBouquetInline, ]

    def save_related(self, request, form, formsets, change):
        # 先调用父类方法保存所有关联的花卉组成条目
        super().save_related(request, form, formsets, change)
        bouquet = form.instance
        # 获取当前花束对应的所有花卉组成
        compositions = CompositionOfTheBouquet.objects.filter(bouquet=bouquet)
        for comp in compositions:
            # 计算需要扣减的库存数量
            deduct_num = comp.count * bouquet.stock
            # 使用F表达式直接在数据库层面更新,避免并发冲突
            Flower.objects.filter(id=comp.flower.id).update(
                stock=F('stock') - deduct_num
            )

补充说明

  • 选用save_related而非save_model,是为了确保所有inline的花卉组成条目都已保存到数据库,才能获取完整的组成数据计算库存扣减。
  • 使用F表达式更新库存,是为了避免多用户同时操作时出现的库存数据不一致问题,直接让数据库完成数值计算,比先取数据再计算再保存更安全。
  • 如果需要支持编辑花束时的库存调整(比如修改花束库存数量、更换花卉或调整数量),还需要额外记录编辑前的旧数据,先反向回滚库存再重新计算扣减,上述代码仅处理新增花束的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 00:31:04