SQLAlchemy IntegrityError违反了约束名称

时间:2014-03-27 17:02:26

标签: python sqlite sqlalchemy

我对数据库表的列有很多不同的约束。插入到数据库中的数据通常包含数字数组(在这些数字上设置了约束),例如(DDL的一部分):

CREATE TABLE "Object" (
    id INTEGER NOT NULL, 
    PRIMARY KEY (id), 
    FOREIGN KEY(id) REFERENCES "Generic" (id)  // Inheritance
);

CREATE TABLE "ObjectData" (
    id INTEGER NOT NULL, 
    x FLOAT NOT NULL, 
    y FLOAT NOT NULL, 
    d FLOAT NOT NULL, 
    a FLOAT NOT NULL, 
    e FLOAT NOT NULL, 
    object_id INTEGER NOT NULL, 
    PRIMARY KEY (id), 
    CONSTRAINT "duplicate x, y values" UNIQUE (x, y, object_id), 
    CONSTRAINT "x must be >= -1.0" CHECK (x >= 0.0), 
    CONSTRAINT "x must be <= 1.0" CHECK (x <= 1.0), 
    CONSTRAINT "y must be >= -1.0" CHECK (y >= -1.0), 
    CONSTRAINT "y must be <= 1.0" CHECK (y <= 1.0), 
    CONSTRAINT "d must be >= -1.0" CHECK (d >= 0.0), 
    CONSTRAINT "d must be <= 1.0" CHECK (d <= 1.0), 
    CONSTRAINT "a must be >= -270.0" CHECK (a >= -270.0), 
    CONSTRAINT "a must be <= 270.0" CHECK (a <= 270.0), 
    CONSTRAINT "e must be >= -1.0" CHECK (e >= -1.0), 
    CONSTRAINT "e must be <= 1.0" CHECK (e <= 1.0), 
    FOREIGN KEY(object_id) REFERENCES "Object" (id)
);

插入数据如下所示(解析为插入数据库的输入文本文件的一部分):

DATA:
-1.0  -1.0  1.0  242.0  0.0
-1.0  -2.0  1.0  124.0  0.0
-1.0  -1.0  1.0  109.0  0.0
...........................
-1.0  -1.0  1.0  242.0  0.0
-1.0  -2.0  1.0  124.0  0.0
-1.0  -1.0  1.0  109.0  0.0

因此,如果这些值中的任何一个违反了约束之一并且没有消息显示,则很难确定哪个值是坏的。为此,给出了约束的描述性名称。通过 SQLAlchemy ORM 执行 SQLite3 数据库,当sqlalchemy.exc.IntegretyError发生时,此库完全切断违反约束的名称。

在SQLite3中的IntegrityError异常中存在约束名称的Google搜索结果已从[版本3.3.2] [1]开始。这显示了Python REPL中的简短测试:

>>> import sqlite3
>>> conn = sqlite3.connect('test/test.db')
>>> c = conn.cursor()
>>> c.execute("""INSERT INTO "ObjectData" (x, y, d, a, e, object_id) VALUES (?, ?, ?, ?, ?, ?)""", (-2.0, -1.0, 1.0, 242.0, 0.0, 1))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
IntegrityError: CHECK constraint failed: x must be >= -1.0

但是当我尝试使用SQLAlchemy插入数据时,我只收到无法描述错误的消息。这里是dir(错误)的结果:

detail = []
params = (-2.0, -1.0, 1.0, 242.0, 0.0, 1)
statement = INSERT INTO "ObjectData" (x, y, d, a, e, object_id) VALUES (?, ?, ?, ?, ?, ?)
instance = <bound method type.instance of <class 'sqlalchemy.exc.IntegrityError'>>
args = ('(IntegrityError) constraint failed',)
orig = constraint failed
orig.message = constraint failed

所以问题是有没有办法强制SQLAlchemy返回违反的约束名称,因为它大大简化了代码并允许向用户显示有关错误的信息性消息?或者可能存在其他方式?

1 个答案:

答案 0 :(得分:1)

我发现SQLAlchemy库使用有什么问题。当我在调试模式下运行软件并在引发IntegrityError异常时断开(在SQLAlchemy库的DBAPIError.instance方法中设置断点)然后我意识到原始错误类型是类'pysqlite2._sqlite.Error'而不是sqlite3。似乎在site-package库中,pysqlite2已经安装在我的Python环境中,但这与sqlite3不同。我尝试使用简单的解决方法:从site-package中删除pysqlite2目录。之后,原始异常类型变为类'sqlite3.Error',而异常中的orig.message包含我期望的内容。很明显SQLAlchemy默认使用pysqlite2库而不是内置的sqlite3库。