如何用SQLAlchemy 1.4映射带UNIQUEIDENTIFIER主键的MS SQL Server表
使用SQLAlchemy 1.4映射MS SQL Server中主键为UNIQUEIDENTIFIER类型的表时遇到一系列问题:
- 最初尝试用
sqlalchemy.String映射,报错无法自增该类型; - 改用
sqlalchemy.dialects.mssql.UNIQUEIDENTIFIER但未设置主键,触发主键组装错误:
class Result(Base): __tablename__ = os.environ["RESULT_TABLE_NAME"] __table_args__ = {"schema": "myschema"} id = Column(UNIQUEIDENTIFIER)
报错:
sqlalchemy.exc.ArgumentError: Mapper mapped class Result->DT_ODS_RESULT could not assemble any primary key columns for mapped table 'DT_ODS_RESULT'
- 添加
primary_key=True后,插入数据时报主键为NULL:
class Result(Base): __tablename__ = os.environ["RESULT_TABLE_NAME"] __table_args__ = {"schema": "SIDODS"} id = Column(UNIQUEIDENTIFIER, primary_key=True)
报错:
sqlalchemy.orm.exc.FlushError: Instance <Result at 0x7fbf9ab99d60> 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.
数据库表已提前设置主键默认值:
ALTER TABLE [SIDODS].[DT_ODS_RESULT] ADD DEFAULT (newid()) FOR [ID]
插入数据的代码如下:
r = Result( query_id=query_id, trigger_id=trigger_id, insertion_datetime=get_datetime_at_timezone() ) session.add(r) session.commit()
要让SQLAlchemy正确识别数据库端生成的UNIQUEIDENTIFIER主键,需在列定义中添加server_default参数,显式告知SQLAlchemy该字段值由数据库服务器生成:
- 导入依赖:
from sqlalchemy import text from sqlalchemy.dialects.mssql import UNIQUEIDENTIFIER from sqlalchemy.ext.declarative import declarative_base Base = declarative_base()
- 正确定义模型类:
class Result(Base): __tablename__ = os.environ["RESULT_TABLE_NAME"] __table_args__ = {"schema": "SIDODS"} id = Column(UNIQUEIDENTIFIER, primary_key=True, server_default=text("newid()")) # 其他字段按实际表结构定义 query_id = Column(...) trigger_id = Column(...) insertion_datetime = Column(...)
关键说明
虽然数据库表已配置默认值,但SQLAlchemy需要明确感知该字段的生成逻辑。通过server_default=text("newid()")配置后:
- 插入数据时,SQLAlchemy不会向该字段传递NULL值,而是交由数据库执行
newid()生成主键; - 会话提交后,SQLAlchemy会自动将数据库生成的ID同步到模型实例中。
此时原有的插入代码无需修改,即可实现无需手动指定ID的自动插入。
内容的提问来源于stack exchange,提问作者Itération 122442

