简体   繁体   English

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

[英]How to set up a table with a recursive foreign key and a relationship declaratively in SQLAlchemy?

Suppose I have a table "nodes" where I store a tree. 假设我有一个存储节点树的表“节点”。 Each node has a primary key id and a column parent_id. 每个节点都有一个主键id和一列parent_id。 Of course, I want to access a parent attribute of each node instance, that is, a relation. 当然,我想访问每个节点实例的父级属性,即一个关系。 One might try: 一个可以尝试:

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)

But when I do that, I get an error: 但是当我这样做时,我得到一个错误:

sqlalchemy.exc.InvalidRequestError: Table 'nodes' is already defined for this MetaData instance. Specify 'useexisting=True' to redefine options and columns on an existing Table object.

I don't understand at what point I could set that option 'useexisting=True' . 我不知道在什么时候可以将该选项设置为'useexisting=True' Is this the right way? 这是正确的方法吗?

EDIT: In fact, the error comes indirectly from another part of the original script. 编辑:实际上,该错误间接来自原始脚本的另一部分。 If one replaces the database path by the temporary database :memory: , it works without problems. 如果用临时数据库:memory:代替数据库路径,则它可以正常工作。 Thanks to TokenMacGuy. 感谢TokenMacGuy。

So the above example can be considered as a working example. 因此,以上示例可以视为一个工作示例。

For some reason, you already have a class registered for that table, or you have defined the table (possibly indirectly) twice. 由于某种原因,您已经为该表注册了一个类,或者已两次(可能是间接地)定义了该表。 This happens to me most frequently when I'm experimenting on the python command line; 在python命令行上进行实验时,这种情况最常见。 sqlalchemy remembers the table definitions and class mappings longer than is immediately obvious (from the lifetime of the actual MetaData instance). sqlalchemy记住表定义和类映射的时间长于立即显而易见的时间(从实际MetaData实例的生命周期开始)。 Make sure you are defining the table only once (exit out of the python interpreter and restart it, if you are in one). 确保只定义一次表(如果在其中,则退出python解释器并重新启动它)。 Other causes why they might be already present is from table reflection, or something has called reload() without really clearing out sys.modules first. 它们可能已经存在的其他原因是由于表反射,或者是在没有真正清除sys.modules情况下调用了reload()

If you are using table reflection, you pass the useexisting=True option to the declarative extension in the __table_args__ class variable: 如果使用表反射,则将useexisting=True选项传递给__table_args__类变量中的声明性扩展:

class Node(Base):
    __tablename__ = "nodes"
    __table_args__ = {"useexisting": True}

But only do that if you are sure that you are defining the table intentionally before you define the python class. 但是只有在确保在定义python类之前故意定义表时才这样做。

If none of these seem to fix the problem, please reduce your module to a minimal example that shows the problem and then post the whole thing in your answer. 如果这些方法都不能解决问题,请将模块缩小为一个显示问题的最小示例,然后将整个内容发布在您的答案中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM