插入操作失败,sqlalchemy中的null Identity键错误+ sqlite
tldr; 尝试将记录插入一个名为json_schema
使用ORM Mapper类的表之后,我收到了错误:sqlalchemy.orm.orm.orm.orm.exc.flusherror:实例:实例< jsonschema,at 0x10657f730>具有NULL身份密钥
。该错误的一部分读取“还确保在不适当的时间(例如在load()事件中)不会发生此flush()。 “在这种情况下,或者如何进一步帮助我解决问题。
在SQLite数据库中,我有一个名为JSON_SCHEMA
的表,看起来像这样。该表中的主要键是由生成的4字节十六进制文本字符串(seals(hex(randyblob(4))))
。
CREATE TABLE json_schema (
id TEXT DEFAULT (lower(hex(randomblob(4)))) NOT NULL,
body JSON NOT NULL,
date_added DATETIME NOT NULL,
title TEXT NOT NULL,
PRIMARY KEY (id)
);
我试图在以下代码中插入一行
# this function inserts one json schema into the json_schemas table for each
# file present in the json_schemas_folder
def load_json_schemas(session, json_schemas_folder):
for obj in json_schemas_folder.glob('**/*'):
if obj.is_file() and obj.suffix == '.json':
title = obj.stem.split('_')[0]
date_added_string = obj.stem.split('_')[1]
date_added = datetime.strptime(date_added_string, '%Y-%m-%d')
body = obj.read_text()
new_row = JsonSchema( # JsonSchema is an ORM-mapper class to the json_schema table
title = title,
body = body,
date_added = date_added
)
# Added row to session here
session.add(new_row)
engine = create_engine('sqlite:///my.db', echo = True)
Session = sessionmaker(bind=engine)
session = Session()
load_json_schemas(session, Path("../data/json_schemas"))
# session.flush() #<-uncommenting this does not resolve the error.
session.commit()
问题:当我执行此脚本时,我遇到了以下错误(在此问题的TLDR部分中引用了该错误):
sqlalchemy.orm.exc.FlushError:
Instance <JsonSchema at 0x10657f730> has a NULL identity key.
If this is an auto-generated value, check that the database table allows generation
of new primary key values, and that the mapped Column object is configured to expect
these generated values. Ensure also that this flush() is not occurring at an inappropriate
time, such as within a load() event.
我检查了中提到的第一个问题此错误 - “检查数据库表是否允许生成新的主要键值” - 通过测试插入insert
(其中ID
不是指定的) 。这有效,因此不是错误的根源。
sqlite> insert into json_schema(body,date_added,title) values ('test','test','test');
sqlite> select * from json_schema;
cee94fc1|test|test|test
接下来,我检查了是否将映射的列对象配置为期望这些生成的值。” 在ORM类中。在下面的摘要中,您可以看到id
列JSonschema
确实具有server_default
设置,这使我相信这一点也是已经解决了。
@declarative_mixin
class DocumentMetadata:
id = Column(Text, nullable=False, primary_key=True, server_default=text('(lower(hex(randomblob(4))))'))
body = Column(JSON, nullable=False)
date_added = Column(DATETIME, nullable=False)
def __repr__(self):
return f"<{self.__class__.__name__}{self.__dict__}>"
@declared_attr
def __tablename__(cls):
return re.sub(r'(?<!^)(?=[A-Z])', '_', cls.__name__).lower()
class JsonSchema(Base, DocumentMetadata):
title = Column(Text, nullable=False)
最后,错误读取“还请确保此flush()不会在不适当的时间(例如Load()事件中发生。 /code>在“适当的时间”发生?
tldr; After trying to insert a record into a table called json_schema
using an ORM mapper class, I received the error: sqlalchemy.orm.exc.FlushError: Instance <JsonSchema at 0x10657f730> has a NULL identity key
. Part of that error read "Ensure also that this flush() is not occurring at an inappropriate time, such as within a load() event.", and I'm not sure what an "inappropriate time" means in this context, or how it can further help me troubleshoot the issue.
In an sqlite database, I have a table called json_schema
that looks like this. The primary key in this table is a 4-byte hexadecimal text string generated by (lower(hex(randomblob(4))))
.
CREATE TABLE json_schema (
id TEXT DEFAULT (lower(hex(randomblob(4)))) NOT NULL,
body JSON NOT NULL,
date_added DATETIME NOT NULL,
title TEXT NOT NULL,
PRIMARY KEY (id)
);
I attempted to insert a row in the following code block
# this function inserts one json schema into the json_schemas table for each
# file present in the json_schemas_folder
def load_json_schemas(session, json_schemas_folder):
for obj in json_schemas_folder.glob('**/*'):
if obj.is_file() and obj.suffix == '.json':
title = obj.stem.split('_')[0]
date_added_string = obj.stem.split('_')[1]
date_added = datetime.strptime(date_added_string, '%Y-%m-%d')
body = obj.read_text()
new_row = JsonSchema( # JsonSchema is an ORM-mapper class to the json_schema table
title = title,
body = body,
date_added = date_added
)
# Added row to session here
session.add(new_row)
engine = create_engine('sqlite:///my.db', echo = True)
Session = sessionmaker(bind=engine)
session = Session()
load_json_schemas(session, Path("../data/json_schemas"))
# session.flush() #<-uncommenting this does not resolve the error.
session.commit()
The problem: when I execute this script, I'm met with the following error (which was referenced earlier in the tldr section of this question):
sqlalchemy.orm.exc.FlushError:
Instance <JsonSchema at 0x10657f730> has a NULL identity key.
If this is an auto-generated value, check that the database table allows generation
of new primary key values, and that the mapped Column object is configured to expect
these generated values. Ensure also that this flush() is not occurring at an inappropriate
time, such as within a load() event.
I checked on the first issue mentioned in this error – "check that the database table allows generation of new primary key values" – by testing an insert INSERT
( where the id
was not specified) . This worked, so not the source of error.
sqlite> insert into json_schema(body,date_added,title) values ('test','test','test');
sqlite> select * from json_schema;
cee94fc1|test|test|test
Next, I checked whether "mapped Column object is configured to expect these generated values." in the ORM class. In the snippet below, you can see that the id
column inhereted by JsonSchema
does have the server_default
set which leads me to believe this point is also already addressed.
@declarative_mixin
class DocumentMetadata:
id = Column(Text, nullable=False, primary_key=True, server_default=text('(lower(hex(randomblob(4))))'))
body = Column(JSON, nullable=False)
date_added = Column(DATETIME, nullable=False)
def __repr__(self):
return f"<{self.__class__.__name__}{self.__dict__}>"
@declared_attr
def __tablename__(cls):
return re.sub(r'(?<!^)(?=[A-Z])', '_', cls.__name__).lower()
class JsonSchema(Base, DocumentMetadata):
title = Column(Text, nullable=False)
Lastly, the error reads "Ensure also that this flush() is not occurring at an inappropriate time, such as within a load() event." How can I determine if flush()
is occurring at an "innapropriate time"?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
sqlalchemy尚未支持SQLITE返回SQLITE ,并且在这种情况下是ISN'ISN''的主要关键t由
自动启动
处理。在这种情况下,SQLalchemy必须执行默认生成的函数本身并明确插入生成的值。为此,要么:
更改
server_default = text('(seals(hex(randyblob(4)))))')
todefault = text = text(' RandomBlob(4)))))
在列定义中
默认
条款add
default = default = text('(seals(hex(randyblob(4))))' )
到列定义,将server_default
留在默认
子句,尽管Sqlalchemy将始终覆盖它。这在,特别是在情况4:不支持主键,返回或等效的部分部分。
第二种方法的新的ORM-Mapper类:
SQLAlchemy does not yet support RETURNING for SQLite, and the primary key in this case isn't handled by
AUTOINCREMENT
. In such a case, SQLAlchemy must execute the default-generating function itself and explicitly insert the generated value.To achieve this, either:
change
server_default=text('(lower(hex(randomblob(4))))')
todefault=text('(lower(hex(randomblob(4))))')
in the column definitionDEFAULT
clauseadd
default=text('(lower(hex(randomblob(4))))')
to the column definition, leavingserver_default
in placeDEFAULT
clause, although SQLAlchemy will always override it.This is documented in Fetching Server-Generated Defaults, in particular in the Case 4: primary key, RETURNING or equivalent is not supported section.
The new ORM-mapper class for the second approach: