如何在发生完整性错误时区分不同的唯一约束

时间:2017-01-05 19:39:51

标签: python-3.x sqlite sqlalchemy

这是一个简单的问题。 我一直在玩SQLAlchemy而我现在处理表中的唯一约束。 因此,当违反Unique Constraint时,会引发IntegrityError异常。如果我为表定义了多个唯一约束,我如何通过引发的异常来区分它们?

编辑: 我在下面使用sqlite3。

最终编辑: AVC答案通过检查违反约束的列的消息错误来提供替代解决方案。它不是一个优雅的解决方案,但它完成了工作。

1 个答案:

答案 0 :(得分:1)

完整性错误将告诉您哪个列违反了约束。对于example

IntegrityError: (IntegrityError) insert or update on table "my_table" 
            violates foreign key constraint "my_table_some_column_fkey"

在你的情况下,你正在声明你的约束:

UniqueConstraint('datapath_port_id', 'datapath_id',
    'controller_id', name='unique_registration')

你在这里做的是声明多个唯一性约束。这看起来像这样:

Column('datapath_port_id', unique=True)
Column('datapath_id', unique=True)
Column('controller_id', unique=True)

相反,您已经创建了多列或复合唯一性约束,这意味着所有三列的组合必须是唯一的。

因此,如果您的数据库行A, B, C具有多列唯一性约束,即使第一行中已存在值A, A, A,您仍可以插入A。同样,B, B, BC, C, C也是有效插入。但是失败的是尝试再次插入A, B, C。这是因为所有列都与现有行匹配,这就是您查看的唯一性错误列出所有列的原因。

以下是代码示例:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer
from sqlalchemy import UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base()


class Test(Base):
    __tablename__ = 'test'
    __table_args__ = (
        UniqueConstraint('a', 'b', name='ab_constraint'),
        UniqueConstraint('b', 'c', name='bc_constraint'))
    id = Column(Integer, primary_key=True)
    a = Column(Integer)
    b = Column(Integer)
    c = Column(Integer)


Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

session.add(Test(a=1, b=1, c=1))
session.add(Test(a=2, b=2, c=2))

从那里我们可以尝试违反不同的唯一性约束来看看会发生什么。如果尝试运行此命令:

session.add(Test(a=1, b=1, c=2))
session.commit()

我们得到:

sqlalchemy.exc.IntegrityError: (IntegrityError) UNIQUE constraint failed: test.a, test.b u'INSERT INTO test (a, b, c) VALUES (?, ?, ?)' (1, 1, 2)

然后如果我们试图违反第二个约束:

session.add(Test(a=1, b=2, c=2))
session.commit()

我们反而得到:

sqlalchemy.exc.IntegrityError: (IntegrityError) UNIQUE constraint failed: test.b, test.c u'INSERT INTO test (a, b, c) VALUES (?, ?, ?)' (1, 2, 2)

第一个案例指定test.atest.b违反了约束,第二个案例指定了test.btest.c

我为这些约束选择的名称ab_constraintbc_constraint)不包含在响应中。然而,它们 存在于数据库级别。我们可以通过回显数据库创建命令来看到这一点:

CREATE TABLE test (
    id INTEGER NOT NULL,
    a INTEGER,
    b INTEGER,
    c INTEGER,
    PRIMARY KEY (id),
    CONSTRAINT ab_constraint UNIQUE (a, b),
    CONSTRAINT bc_constraint UNIQUE (b, c)
)

但是,即使在数据库级别(我使用SQLite),错误消息中也没有使用约束名称:

sqlite> INSERT INTO test (a, b, c) VALUES (1, 1, 1);
sqlite> INSERT INTO test (a, b, c) VALUES (2, 2, 2);
sqlite> INSERT INTO test (a, b, c) VALUES (1, 1, 2);
Error: UNIQUE constraint failed: test.a, test.b