【问题标题】:Flask SQLAlchemy unique constraint on multiple columns with a given valueFlask SQLAlchemy对具有给定值的多个列的唯一约束
【发布时间】:2021-04-24 18:33:47
【问题描述】:

假设我有两张桌子

订单表

class Order(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  deliveries = db.relationship("Delivery", back_populates="order")

交货表

class Delivery(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  status= db.Column(db.String(20))
  order_id = db.Column(db.Integer, db.ForeignKey('order.id'), nullable=False)
  order = db.relationship("Order", back_populates="deliveries")

一个订单可能有多个交货。交付表的状态字段有以下可能的值["Planned", "Failed", "Delivered"]

问题: 如何确保一个订单没有两个计划交货?

提示: 我知道我可以对多个表实施唯一约束,例如在交付模式中添加下一行

__table_args__ = (db.UniqueConstraint('order_id', 'status', name='_order_status_uc'))

但是通过这样做,我将防止一个订单出现两次失败的交付。

任何帮助将不胜感激,因为我想直接在数据库中强制执行此约束。

【问题讨论】:

  • 你使用的数据库引擎是什么?
  • 我在使用 PostgreSQL

标签: flask sqlalchemy flask-sqlalchemy


【解决方案1】:

更新(假设是 PostgreSQL)

鉴于您使用 PostgreSQL,最直接的解决方案是使用Partial Unique Index

CREATE UNIQUE INDEX _order_status_uc ON delivery (order_id) WHERE status = 'Planned';

如果你使用 SQLAlchemy 创建索引,下面应该是等价的:

类交付(基础): # ...

__table_args__ = (
    Index(
        '_order_status_uc',
        'order_id',
        unique=True,
        postgresql_where=(status == 'Planned'),
    ),
)

原答案

假设您使用的 RDBMS 支持这一点,一种实现思路是:

  • delivery 表上创建一个计算列,对于“已计划”statusNULL 的值为 order_id 否则
  • 在此计算列上创建一个UNIQUE Constraint

这假设以下关于使用的 RDBMS:

  1. 计算列不仅受支持,还可以成为索引/约束的一部分。
  2. UNIQUE 索引的实现允许多个NULL 值。

请参阅PostgreSQL unique constraint null: Allowing only one Null 文章了解更多背景信息。

【讨论】:

  • 我相信有人会想出一个限制更宽松的解决方案。
  • 如果是 PostgreSQL,order_id 上带有status = 'Planned' 的部分唯一索引?我敢打赌,这就是您已经询问过 DBMS 的原因。
  • 到目前为止,我还没有找到合适的约束实现。这个提议是一种解决方法,我接受了。非常感谢@van
【解决方案2】:

您可以使用当前订单ID和计划状态查询您的交付模式,如果有结果,请进行验证。

planned_delivery_exist_boolean = db.session.query(Delivery).filter(Delivery.order_id==order_id).filter(Delivery.status=="Planned").first()

if planned_delivery_exist_boolean:
    # trigger validation error

【讨论】:

  • 这只能在 ORM 级别上工作。我想要一些关于数据库级别的东西,为什么要寻找 db 约束
猜你喜欢
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
  • 2019-09-06
  • 2017-11-18
  • 1970-01-01
  • 2010-12-22
  • 1970-01-01
  • 2015-02-27
相关资源
最近更新 更多