Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在SQLAlchemy中以声明方式设置具有递归外键和关系的表?_Python_Foreign Keys_Sqlalchemy_Foreign Key Relationship - Fatal编程技术网

Python 如何在SQLAlchemy中以声明方式设置具有递归外键和关系的表?

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.

假设我有一个表“nodes”,其中存储了一棵树。每个节点都有一个主键id和一个列父节点id。 当然,我希望访问每个节点实例的父属性,即关系。 人们可以尝试:

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表上指定外键约束。