Множество самоссылочных отношений в SQLAlchemy - PullRequest
7 голосов
/ 12 февраля 2011

У меня есть модель базы данных, где мне нужны отношения один-ко-многим и два отношения один-к-одному.Вот модель, которую я сделал, но она выдает ошибки

class Page(Base):
    __tablename__ = 'pages'
    id          = Column(Integer, primary_key=True)
    title       = Column(String(100), nullable=False)
    content     = Column(Text, nullable=False)

    parent_id   = Column(Integer, ForeignKey("pages.id"), nullable=True)
    children    = relationship("Page", backref=backref("parent", remote_side=id))

    next_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    next        = relationship("Page", backref=backref("prev", remote_side=id, uselist=False))

    prev_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    prev        = relationship("Page", backref=backref("next", remote_side=id, uselist=False))

    def __init__(self, title, content, parent_id=None, next_id=None, prev_id=None):
        self.title = title
        self.content = content
        self.parent_id = parent_id
        self.next_id = next_id
        self.prev_id = prev_id

    def __repr__(self):
        return '<Page "%r">' % self.title

Я получаю следующую ошибку всякий раз, когда пытаюсь что-то сделать с базой данных

ArgumentError: Could not determine join condition between parent/child tables on relationship Page.children. Specify a 'primaryjoin' expression. If 'secondary' is present, 'secondaryjoin' is needed as well.

Что действительно странно, так этоработал без следующих и предыдущих столбцов.Кто-нибудь знает, что не так?

Ответы [ 2 ]

14 голосов
/ 04 мая 2011

Тема старая, но так как это так запутанно, я запишу ее.
Вам не нужен отдельный столбец «prev», у вас уже есть его в качестве backref для «next». Кроме того, поскольку у вас есть несколько внешних ключей для одной и той же цели, вам необходимо указать первичные объединения вручную:

class Page(Base):
    __tablename__ = 'pages'
    id          = Column(Integer, primary_key=True)
    title       = Column(String(100), nullable=False)
    content     = Column(Text, nullable=False)

    parent_id   = Column(Integer, ForeignKey("pages.id"), nullable=True)
    parent      = relationship("Page",
                    primaryjoin=('pages.c.id==pages.c.parent_id'),
                    remote_side='Page.id',
                    backref=backref("children" ))

    next_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    next        = relationship("Page", 
                    primaryjoin=('pages.c.next_id==pages.c.id'),
                    remote_side='Page.id', 
                    backref=backref("prev", uselist=False))

Я заметил пару ошибок или просто странное поведение:
- Вы можете использовать только remote_side="Page.id", а не remote_side=[id] и не remote_side=["Page.id"], иначе это не сработает (sqlalchemy 0.6.6). Это было раздражающим, чтобы придавить.
- Похоже, вы всегда должны использовать remote_side с первичным ключом, независимо от того, что вы на самом деле является удаленной стороной. remote_side="Pages.next_id" всегда генерирует странную ошибку, даже если это кажется уместным.
- Выражение primaryjoin вводит в заблуждение, поскольку оно не использует псевдонимы, но на самом деле это правильный способ сделать это. Механизм привязки знает, какое выражение заменить параметром (что слишком неявно и против Дзен, кстати).

1 голос
/ 08 января 2016

Вы можете использовать foreign_keys:

class Page(Base):
    __tablename__ = 'pages'
    id          = Column(Integer, primary_key=True)
    title       = Column(String(100), nullable=False)
    content     = Column(Text, nullable=False)

    parent_id   = Column(Integer, ForeignKey("pages.id"), nullable=True)
    parent      = relationship("Page",
                    foreign_keys=[parent_id],
                    remote_side=[id],
                    backref=backref("children" ))

    next_id     = Column(Integer, ForeignKey("pages.id"), nullable=True)
    next        = relationship("Page", 
                    foreign_keys=[next_id],
                    remote_side=[id], 
                    backref=backref("prev", uselist=False))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...