Reputation: 50544
I have two tables, foo
and bar
, and I want foo.bar_id
to link to bar
. The catch is that this is a one-way one-to-one relationship. bar
must not know anything about foo
. For every foo, there will be one and only one bar
.
Ideally, after selecting a foo, I could do something like this:
myfoo.bar.whatever = 5
How to accomplish this?
Upvotes: 70
Views: 73367
Reputation: 1814
The documentation explains this nicely:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child = relationship("Child", uselist=False, backref="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
OR
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child", backref=backref("parent", uselist=False))
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
Note: The API and associated documentation has changed considerably since the answer was written. New docs
Upvotes: 150
Reputation: 19817
Other answers using uselist=False
are correct, but in SQLAlchemy 2.0 relationship
is now smart enough to deduce it if your Mapped
annotation uses a non-collection type.
From the docs:
New in version 2.0: The
relationship()
construct can derive the effective value of therelationship.uselist
parameter from a givenMapped
annotation.
Here is chadwick.boulay’s code modified for SqlAlchemy 2.0:
class Parent(Base):
__tablename__ = 'parent'
id: Mapped[int] = mapped_column(Integer(), primary_key=True)
child: Mapped["Child"] = relationship("Child", backref="parent")
class Child(Base):
__tablename__ = 'child'
id: Mapped[int] = mapped_column(Integer(), primary_key=True)
parent_id: Mapped[int] = mapped_column(Integer(), ForeignKey('parent.id'))
Notice how child
is annotated with Mapped["Child"]
, i.e. child
is one Child
. If you wanted to use a one-to-many relationship, you would annotate it as a list:
children: Mapped[List["Child"]] = relationship("Child", backref="parent")
Upvotes: 3
Reputation: 4685
I think if it is a truly one to one relationship we should add a uniqueness constraint to foreign key so another parent can not have other parent child!! Like this:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'), unique=True)
child = relationship("Child", backref=backref("parent", uselist=False))
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
Upvotes: 12
Reputation: 3308
If you want a true one-to-one relationship, you also have to use the "uselist=False" in your relationship definition.
bar_id = Column(Integer, ForeignKey(Bar.id))
bar = relationship(Bar, uselist=False)
Upvotes: 60
Reputation: 50544
It turns out this is actually quite easy. In your Foo model:
bar_id = Column(Integer, ForeignKey(Bar.id))
bar = relationship(Bar)
Upvotes: 3