Python 如何在SQLAlchemy中以声明方式设置具有递归外键和关系的表?
假设我有一个表“nodes”,其中存储了一棵树。每个节点都有一个主键id和一个列父节点id。 当然,我希望访问每个节点实例的父属性,即关系。 人们可以尝试:Python 如何在SQLAlchemy中以声明方式设置具有递归外键和关系的表?,python,foreign-keys,sqlalchemy,foreign-key-relationship,Python,Foreign Keys,Sqlalchemy,Foreign Key Relationship,假设我有一个表“nodes”,其中存储了一棵树。每个节点都有一个主键id和一个列父节点id。 当然,我希望访问每个节点实例的父属性,即关系。 人们可以尝试: import sqlalchemy, sqlalchemy.orm, sqlalchemy.ext.declarative engine = sqlalchemy.create_engine('sqlite:///PATHTOMYDATABASE', echo=True) Base = sqlalchemy.ext.declarative.
import sqlalchemy, sqlalchemy.orm, sqlalchemy.ext.declarative
engine = sqlalchemy.create_engine('sqlite:///PATHTOMYDATABASE', echo=True)
Base = sqlalchemy.ext.declarative.declarative_base()
class Node(Base):
__tablename__ = "nodes"
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
parent_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("nodes.id"))
parent = sqlalchemy.orm.relationship("Node", backref=sqlalchemy.orm.backref("childs"))
Base.metadata.create_all(engine)
但当我这样做时,我会得到一个错误:
sqlalchemy.exc.InvalidRequestError:已为此元数据实例定义了表“节点”。指定“useexisting=True”以重新定义现有表对象上的选项和列。
我不明白在什么时候可以设置该选项'useexisting=True'
。这条路对吗
编辑:事实上,错误间接来自原始脚本的另一部分。如果将数据库路径替换为临时数据库:memory:
,则它可以正常工作。多亏了他
因此,上面的示例可以看作是一个工作示例。出于某种原因,您已经为该表注册了一个类,或者您已经定义了该表两次(可能是间接的)。当我在python命令行上进行实验时,这种情况最常见;sqlalchemy记住表定义和类映射的时间比显而易见的要长(从实际元数据实例的生存期开始)。确保只定义一次表(退出python解释器并重新启动它,如果在python解释器中)。它们可能已经存在的其他原因是表反射,或者在没有真正清除系统模块的情况下调用了
reload()
如果使用的是表反射,则将useexisting=True
选项传递给\uuu table\u args\uu
类变量中的声明性扩展:
class Node(Base):
__tablename__ = "nodes"
__table_args__ = {"useexisting": True}
但是,只有在确定在定义python类之前有意地定义了表时,才能这样做
如果这些似乎都不能解决问题,请将模块简化为显示问题的最小示例,然后在答案中发布整个内容。出于某种原因,您已经为该表注册了一个类,或者您已经(可能间接)两次定义了该表。当我在python命令行上进行实验时,这种情况最常见;sqlalchemy记住表定义和类映射的时间比显而易见的要长(从实际元数据实例的生存期开始)。确保只定义一次表(退出python解释器并重新启动它,如果在python解释器中)。它们可能已经存在的其他原因是表反射,或者在没有真正清除系统模块的情况下调用了
reload()
如果使用的是表反射,则将useexisting=True
选项传递给\uuu table\u args\uu
类变量中的声明性扩展:
class Node(Base):
__tablename__ = "nodes"
__table_args__ = {"useexisting": True}
但是,只有在确定在定义python类之前有意地定义了表时,才能这样做
如果这些似乎都不能解决问题,请将您的模块简化为显示问题的最小示例,然后在您的答案中发布整个内容。谢谢!事实上,当创建最小的示例时,它似乎是有效的。我将首先查找我的错误。您是对的,我的问题是在定义表之前使用
元数据.reflect(engine)
。只要在节点
的声明中没有定义列
,此操作就有效。如果节点
声明包含列,我可能应该省略metadata.reflect(engine)
。如果愿意,可以使用表反射。除了反射之外,您希望使用列定义的主要原因是反射错误地获取了一些细节;您可能希望tinyint
列为布尔值,或者(最常见的)指定MySQL MyISAM表上的外键约束。谢谢!事实上,当创建最小的示例时,它似乎是有效的。我将首先查找我的错误。您是对的,我的问题是在定义表之前使用元数据.reflect(engine)
。只要在节点
的声明中没有定义列
,此操作就有效。如果节点
声明包含列,我可能应该省略metadata.reflect(engine)
。如果愿意,可以使用表反射。除了反射之外,您希望使用列定义的主要原因是反射错误地获取了一些细节;您可能希望tinyint
列为布尔值,或者(最常见的)在MySQL MyISAM表上指定外键约束。