Django生鲜电商订单模型实现:一对多关联商品明细需求
解决方案:重构订单模型并实现Admin表格式明细展示
一、模型结构重构
将原有单一订单模型拆分为订单主表和订单明细两个模型,实现一对多关联:
# 商品详情模型保持不变 class ProductDetails(models.Model): name= models.CharField(max_length=100) price= models.FloatField() mrp= models.FloatField() main_img = models.ImageField(upload_to='product_img') img1 = models.ImageField(upload_to='product_img') img2 = models.ImageField(upload_to='product_img') img3 = models.ImageField(upload_to='product_img') category = models.ForeignKey(Category, related_name='produits', on_delete=models.CASCADE) subcategory = models.ForeignKey(SubCategory, related_name='produits', on_delete=models.CASCADE) product_details = RichTextField(blank=True, null=True) trending = models.BooleanField(default=False) def __str__(self): return self.name # 订单主表:存储订单整体信息 class Order(models.Model): order_id = models.CharField(max_length=100, unique=True, default="") customer_name = models.ForeignKey(User, related_name='orders', on_delete=models.CASCADE) # 修正原拼写错误 date = models.DateTimeField(auto_now_add=True) # 自动生成订单创建时间 address = models.CharField(max_length=500) mobile_no = models.CharField(max_length=12) order_state_list = [ ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('confirm', 'Confirm'), ('on_the_way', 'On the way'), ('delivered', 'Delivered'), ] order_status = models.CharField(max_length=50, choices=order_state_list, default="pending") payment_state_list = [ ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('confirm', 'Confirm') ] payment_status = models.CharField(max_length=50, choices=payment_state_list, default="pending") transaction_id = models.CharField(max_length=100) def get_total_cost(self): # 实时汇总订单所有明细的总金额 return sum(item.get_item_total() for item in self.order_items.all()) def __str__(self): return f"Order {self.order_id} - {self.customer_name.username}" # 订单明细:存储单个商品的购买信息 class OrderItem(models.Model): order = models.ForeignKey(Order, related_name='order_items', on_delete=models.CASCADE) product = models.ForeignKey(ProductDetails, related_name='order_items', on_delete=models.CASCADE) quantity = models.IntegerField(default=1) price = models.FloatField() # 保存下单时的商品价格,避免后续价格变动影响历史订单 def get_item_total(self): # 计算单个明细的总价 return self.price * self.quantity def __str__(self): return f"{self.quantity} x {self.product.name}"
二、Django Admin配置实现表格式明细展示
使用TabularInline将订单明细嵌入订单编辑页面,实现类似Odoo One2Many的表格式编辑效果:
from django.contrib import admin from .models import Order, OrderItem, ProductDetails # 定义订单明细内联组件 class OrderItemInline(admin.TabularInline): model = OrderItem extra = 1 # 默认显示1个空的明细输入行 fields = ('product', 'quantity', 'price') readonly_fields = ('price',) # 自动填充商品价格时设为只读 # 自动填充下单时的商品当前价格 def save_model(self, request, obj, form, change): if not obj.price: obj.price = obj.product.price super().save_model(request, obj, form, change) # 配置订单Admin页面 @admin.register(Order) class OrderAdmin(admin.ModelAdmin): list_display = ('order_id', 'customer_name', 'date', 'order_status', 'payment_status', 'get_total_cost') inlines = [OrderItemInline] # 关联明细内联组件 readonly_fields = ('date', 'get_total_cost') # 禁止修改创建时间和总金额 # 商品详情Admin保持原有配置 @admin.register(ProductDetails) class ProductDetailsAdmin(admin.ModelAdmin): list_display = ('name', 'price', 'mrp', 'category', 'trending')
三、关键注意事项
- 数据迁移:修改模型后执行
python manage.py makemigrations和python manage.py migrate更新数据库,原有订单数据需手动迁移或编写迁移脚本。 - 订单ID生成:可在
Order的save方法中自动生成唯一订单ID(如时间戳+随机字符串),避免手动输入重复。 - 价格一致性:
OrderItem的price字段保存下单时的商品价格,确保历史订单金额不受后续商品调价影响。 - 总金额优化:若需频繁查询订单总金额,可在
Order中添加total_cost字段,通过信号或保存方法自动更新,替代实时计算。
内容的提问来源于stack exchange,提问作者Chetan Rathod
相关产品推荐
相关产品推荐

