当INSERT没有返回任何行时,SQLAlchemy引发TypeError?

时间:2013-01-15 04:20:53

标签: python postgresql sqlalchemy

我有一个这样的插入语句:

insert = MyTable.insert()
row = {"foo": 42}
result = cxn.execute(insert, row)

但是Postgres触发器将插入从mytable重定向到新表,因此insert语句实际上不会返回任何内容:

# INSERT INTO mytable VALUES (DEFAULT, 'stuff') RETURNING LASTVAL();
 lastval 
---------
(0 rows)

这导致SQLAlchemy(0.8b2)引发TypeError: 'NoneType' is not subscriptable。当DefaultExecutionContext尝试获取插入行的主键时,看起来会发生这种情况。

这是一个应该报告的错误吗?有什么方法可以解决这个问题,告诉SQLAlchemy不要期望返回值吗?

追溯

… snip… 
  File "myfile.py", line 85, in store
    result = cxn.execute(insert, row)
  File ".../sqlalchemy/engine/base.py", line 664, in execute
    params)
  File ".../sqlalchemy/engine/base.py", line 764, in _execute_clauseelement
    compiled_sql, distilled_params
  File ".../sqlalchemy/engine/base.py", line 899, in _execute_context
    context._fetch_implicit_returning(result)
  File ".../sqlalchemy/engine/default.py", line 697, in _fetch_implicit_returning
    ipk.append(row[c])
TypeError: 'NoneType' object is not subscriptable

Postgres触发器

CREATE OR REPLACE FUNCTION mytable_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO mytable_cur VALUES (NEW.*);
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER mytable_insert_trigger
    BEFORE INSERT ON mytable
    FOR EACH ROW EXECUTE PROCEDURE mytable_insert_trigger();

2 个答案:

答案 0 :(得分:2)

你在这里违反了合同。对于Postgres后端,SQLAlchemy将倾向于使用INSERT ... RETURNING以便它可以检索例如来自生成序列的值。你正在插入一行但却在说谎。

基于the documentation,我认为你想要使用INSTEAD OF触发器而不是BEFORE,并使NEW行保持不变。 Postgres会假设你做了必要的插入,只是将返回的行传回客户端。

答案 1 :(得分:1)

是的,您可以通过关闭implicit_returning来回退到获取最后插入的id的旧系统,您可以为表执行此操作:

Table('sometable', metadata, ... columns ..., implicit_returning=False)

会发生什么,假设这是一个直接的SERIAL主键,它将事先显式执行“tablename_id_seq”,并在INSERT语句中使用该值。