如何为Peewee的Transaction模型设置金额与买卖方约束?
解决Peewee模型的两个约束问题
你已经定义了以下Peewee模型:
class Product(peewee.Model): description = peewee.CharField() price_in_cents = peewee.IntegerField() stock = peewee.IntegerField() tags = peewee.ManyToManyField(Tag) class Meta: database = db class Transaction(peewee.Model): seller = peewee.ForeignKeyField(User) buyer = peewee.ForeignKeyField(User) product = peewee.ForeignKeyField(Product) amount = peewee.IntegerField()
针对你需要的两个约束,这里提供两种实现思路:应用层验证(灵活易维护)和数据库层约束(更可靠)。
约束1:Transaction的amount不超过对应Product的库存
方法1:应用层验证(重写save方法)
在Transaction模型中重写save()方法,保存前检查购买数量是否超出库存:
class Transaction(peewee.Model): seller = peewee.ForeignKeyField(User) buyer = peewee.ForeignKeyField(User) product = peewee.ForeignKeyField(Product) amount = peewee.IntegerField() def save(self, *args, **kwargs): # 获取最新商品库存,避免缓存旧数据 product = Product.get_by_id(self.product.id) if self.amount > product.stock: raise ValueError("购买数量不能超过商品当前库存") super().save(*args, **kwargs)
方法2:数据库层CHECK约束
如果你的数据库支持跨表CHECK约束(如PostgreSQL、SQLite 3.33+),可直接在模型Meta中添加约束:
class Transaction(peewee.Model): seller = peewee.ForeignKeyField(User) buyer = peewee.ForeignKeyField(User) product = peewee.ForeignKeyField(Product) amount = peewee.IntegerField() class Meta: database = db constraints = [ peewee.Check('amount <= (SELECT stock FROM product WHERE id = product_id)') ]
约束2:seller与buyer不能为同一用户
方法1:应用层验证(重写save方法)
在save方法中添加身份检查:
class Transaction(peewee.Model): seller = peewee.ForeignKeyField(User) buyer = peewee.ForeignKeyField(User) product = peewee.ForeignKeyField(Product) amount = peewee.IntegerField() def save(self, *args, **kwargs): if self.seller.id == self.buyer.id: raise ValueError("卖家和买家不能是同一用户") # 同时加入库存验证 product = Product.get_by_id(self.product.id) if self.amount > product.stock: raise ValueError("购买数量不能超过商品当前库存") super().save(*args, **kwargs)
方法2:数据库层CHECK约束
直接添加字段间的不等约束:
class Transaction(peewee.Model): seller = peewee.ForeignKeyField(User) buyer = peewee.ForeignKeyField(User) product = peewee.ForeignKeyField(Product) amount = peewee.IntegerField() class Meta: database = db constraints = [ peewee.Check('seller_id != buyer_id'), peewee.Check('amount <= (SELECT stock FROM product WHERE id = product_id)') ]
两种方案对比
- 应用层验证:逻辑更灵活,可结合复杂业务规则,适合大多数场景;但需确保所有写入操作都通过模型的save方法执行。
- 数据库层约束:直接在数据库层面限制,能防止绕过应用层的非法写入(如直接操作数据库),但依赖数据库对CHECK约束的支持程度。
内容的提问来源于stack exchange,提问作者Maya Kroft
相关产品推荐
相关产品推荐

