Django Admin中save_model函数失效,订单库存校验逻辑未执行求助
问题原因
当你在Admin中使用OrderItemInline时,save_model方法只会先完成Order主对象的保存,此时Inline中的OrderItem还未写入数据库。所以你在save_model里遍历obj.orderitem_set.all()根本拿不到刚添加的订单项,自然库存校验和扣减逻辑完全没执行。
修复方案
改用Django Admin提供的save_formset方法,这个方法专门用于处理Inline表单集的保存流程,能获取到所有待处理的OrderItem数据。同时结合数据库事务,确保一旦校验失败,所有已保存的数据都会回滚,避免数据不一致。
修改后的OrderAdmin代码如下:
from django.contrib import admin from django.contrib import messages from django.utils.translation import ngettext from .models import Category, Product, Order, OrderItem from django.utils.html import format_html from django.db import transaction # 导入事务 class OrderItemInline(admin.TabularInline): model = OrderItem extra = 1 class OrderAdmin(admin.ModelAdmin): inlines = [OrderItemInline] list_display = ('id', 'user', 'order_date') @transaction.atomic # 开启原子事务,出错自动回滚 def save_formset(self, request, form, formset, change): errors = [] # 先获取所有待保存的OrderItem对象(不立即写入数据库) order_items = formset.save(commit=False) # 批量做库存校验 for order_item in order_items: if order_item.quantity > order_item.product.quantity: errors.append( f"商品【{order_item.product.name}】订购数量({order_item.quantity})超过库存({order_item.product.quantity})" ) if errors: # 有错误就提示,终止保存流程 message = ngettext( "订单未保存,原因:", "订单未保存,原因:", len(errors), ) messages.error(request, f"{message} {';'.join(errors)}") return # 校验通过,先保存订单项到数据库 formset.save() # 批量扣减库存 for order_item in order_items: order_item.product.quantity -= order_item.quantity order_item.product.save() # 执行父类的保存逻辑 super().save_formset(request, form, formset, change) # 其他Admin注册代码保持不变 admin.site.register(Category) class ProductAdmin(admin.ModelAdmin): list_display = ['display_image', 'name', 'quantity', 'price', 'category'] def display_image(self, obj): if obj.image: return format_html('<img src="{}" width="50" height="50" />'.format(obj.image.url)) return "无图片" display_image.short_description = '图片' admin.site.register(Product,ProductAdmin) admin.site.register(Order, OrderAdmin)
额外说明
@transaction.atomic装饰器确保整个保存流程是原子性的,只要有一个订单项校验失败,所有已执行的数据库操作都会回滚,避免出现订单保存但库存未扣减、或库存扣减但订单未保存的不一致情况。formset.save(commit=False)生成OrderItem对象但不立即写入数据库,方便我们先完成全量校验,再统一执行保存操作。- 先收集所有错误再统一提示,能让用户一次性看到所有问题,提升操作体验。
内容的提问来源于stack exchange,提问作者Praveen
相关产品推荐
相关产品推荐

