Как настроить таблицу с рекурсивным внешним ключом и декларативным отношением в SQLAlchemy? - PullRequest
0 голосов
/ 25 августа 2011

Предположим, у меня есть таблица "узлов", где я храню дерево.Каждый узел имеет идентификатор первичного ключа и столбец parent_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: Table 'nodes' is already defined for this MetaData instance. Specify 'useexisting=True' to redefine options and columns on an existing Table object.

Я не понимаю, в какой момент я мог установитьэтот вариант 'useexisting=True'.Это правильный путь?

РЕДАКТИРОВАТЬ: На самом деле, ошибка происходит косвенно из другой части исходного сценария.Если один из них заменяет путь к временной базе данных :memory:, он работает без проблем.Благодаря TokenMacGuy.

Так что приведенный выше пример можно рассматривать как рабочий пример.

1 Ответ

5 голосов
/ 25 августа 2011

По какой-то причине у вас уже есть класс, зарегистрированный для этой таблицы, или вы определили таблицу (возможно, косвенно) дважды. Это случается со мной чаще всего, когда я экспериментирую с командной строкой python; sqlalchemy запоминает определения таблиц и сопоставления классов дольше, чем это сразу видно (из времени существования фактического экземпляра MetaData). Убедитесь, что вы определяете таблицу только один раз (выйдите из интерпретатора Python и перезапустите его, если вы в нем). Другие причины, по которым они могут уже присутствовать, связаны с отражением в таблице, или что-то вызвало reload() без реального удаления сначала sys.modules.

Если вы используете отражение таблицы, вы передаете опцию useexisting=True декларативному расширению в переменной класса __table_args__:

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

Но делайте это только в том случае, если вы уверены , что вы намеренно определяете таблицу до того, как определите класс python.

Если ни одна из этих проблем не помогает устранить проблему, уменьшите модуль до минимального примера, который показывает проблему, а затем опубликуйте все это в своем ответе.

...