使用SQLAlchemy v1.4向继承表添加行时遇非空列NULL错误
问题
为演示需求,涉及四张表:ModelType、ModelTypeA、ModelTypeB、Model,需通过SQLAlchemy v1.4实现指定的表继承关联关系。已通过以下代码定义实体类并成功创建表结构:
Base = declarative_base() class ModelType(Base): __tablename__ = "modeltype" id = Column(Integer, primary_key=True) algorithm = Column(String) models = relationship("Model", back_populates="modeltype") __mapper_args__ = { "polymorphic_identity": "modeltype", "polymorphic_on": algorithm } def __repr__(self): return f"{self.__class__.__name__}({self.algorithm!r})" class ModelTypeA(ModelType): __tablename__ = "modeltypea" id = Column(Integer, ForeignKey("modeltype.id"), primary_key=True) parameter_a = Column(Integer) __mapper_args__ = { "polymorphic_identity": "Model Type A" } class ModelTypeB(ModelType): __tablename__ = "modeltypeb" id = Column(Integer, ForeignKey("modeltype.id"), primary_key=True) parameter_a = Column(Integer) __mapper_args__ = { "polymorphic_identity": "Model Type B" } class Model(Base): __tablename__ = "model" id = Column(Integer, primary_key=True) trainingtime = Column(Integer) modelversionid = Column(Integer, ForeignKey("modeltype.id")) modeltype = relationship("ModelType", back_populates="models") def __repr__(self) -> str: return f"Model(id={self.id!r}, trainingtime={self.trainingtime!r})"
创建表的代码及生成的SQL语句均正常,但执行以下添加入行操作时:
model_type_a = ModelTypeA(parameter_a=3) model = Model(trainingtime=10, modeltype=model_type_a) session.add(model) session.commit()
出现SAWarning警告:列'modeltypea.id'作为主键无默认值且未传值,随后触发sqlalchemy.exc.IntegrityError错误:非空列出现NULL结果。推测创建ModelTypeA实例时未在ModelType表生成对应行,导致无可用id关联,请问该继承表场景下应如何正确添加入行?
解决方案
这个问题出在SQLAlchemyjoined-table继承的配置上,子类表的主键需要和父类主键自动同步值,只需修改子类的id字段配置即可解决:
- 给子类的
id字段添加autoincrement=False参数,明确该字段的值完全依赖父类主键生成,不需要自身自增逻辑
修正后的子类代码如下:
class ModelTypeA(ModelType): __tablename__ = "modeltypea" # 添加autoincrement=False,指定字段值由父类主键同步 id = Column(Integer, ForeignKey("modeltype.id"), primary_key=True, autoincrement=False) parameter_a = Column(Integer) __mapper_args__ = { "polymorphic_identity": "Model Type A" } class ModelTypeB(ModelType): __tablename__ = "modeltypeb" id = Column(Integer, ForeignKey("modeltype.id"), primary_key=True, autoincrement=False) parameter_a = Column(Integer) __mapper_args__ = { "polymorphic_identity": "Model Type B" }
修改后原插入代码无需调整,执行session.commit()时,SQLAlchemy会自动完成以下流程:
- 先向
ModelType表插入数据,生成主键id - 将该主键值同步到
ModelTypeA表的id字段,完成子类数据插入 - 最后插入
Model表数据并关联对应的外键值
内容的提问来源于stack exchange,提问作者Luca Guarro
相关产品推荐
相关产品推荐

