One to one self relationship in SQLAlchemy

Question:

I need to create an SQLAlchemy version of a linked list. It’s actually more complex than that, but it boils down to this:

I need a one-to-one, self-referential, bidirectional relationship in a class. Every element may only have a single parent or none at all, and up to one child.

I simplified my class so it looks like this:

class Node(declarative_base()):
    __tablename__ = 'nodes'

    id = Column(Integer, Sequence('nodes_id_seq'), primary_key=True, autoincrement=True)
    value = Column(Integer)
    prev_node_id = Column(Integer, ForeignKey('nodes.id'))
    next = relationship('Node', uselist=False, backref=backref('prev', uselist=False))

However, when I try to create one, it throws an exception:

>>> Node()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "<string>", line 2, in __init__
  File "sqlalchemyorminstrumentation.py", line 309, in _new_state_if_none
    state = self._state_constructor(instance, self)

[...]

  File "sqlalchemyormproperties.py", line 1418, in _generate_backref
    self._add_reverse_property(self.back_populates)
  File "sqlalchemyormproperties.py", line 871, in _add_reverse_property
    % (other, self, self.direction))
ArgumentError: Node.next and back-reference Node.prev are both of the same direction <symbol 'ONETOMANY>.  Did you mean to set remote_side on the many-to-one side ?

What am I missing here? Google search got me absolutely nowhere… :/

Asked By: ewino

||

Answers:

As exception says you need to set remote_side keyword for relationship. Otherwise sqlalchemy cannot select reference direction.

class Node(declarative_base()):
    ...
    prev = relationship(
        'Node',
        uselist=False,
        remote_side=[id],
        backref=backref('next', uselist=False)
    )
Answered By: Aleksandr Dezhin

With the current version of the ORM there are breaking changes you should consider.

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class Node(db.Models):
    ...
    prev = db.relationship('Prev', backref='node', uselist=False)
Answered By: Miebaka
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.