I am trying to use sqlalchemy
to model a database consisting of two classes A
and B
. The B
class has two fields: B.a
(1 to n) and B.alist
(n to n).
I am trying to follow the Setting Bi-Directional Many-to-many example (see the code below), but I get the following warning:
SAWarning: relationship 'A.blist' will copy column a.id to column b.a_id, which conflicts with relationship(s): 'A.bs' (copies a.id to b.a_id). If this is not the intention, consider if these relationships should be linked with back_populates, or if viewonly=True should be applied to one or more if they are read-only. For the less common case that foreign key constraints are partially overlapping, the orm.foreign() annotation can be used to isolate the columns that should be written towards. To silence this warning, add the parameter 'overlaps="bs"' to the 'A.blist' relationship. (Background on this warning at: ) (This warning originated from the
configure_mappers()
process, which was invoked automatically in response to a user-initiated operation.)
How should I model this to have a B
class with one instance of A
in B.a
and other instances in B.alist
?:
from typing import List
from sqlalchemy import ForeignKey, Table, Column, Integer
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
class Base(DeclarativeBase):
pass
associative_table = Table(
"associative_table",
Base.metadata,
Column("a_id", Integer, ForeignKey("a.id"), primary_key=True),
Column("b_id", Integer, ForeignKey("b.id"), primary_key=True),
)
class A(Base):
__tablename__ = 'a'
id: Mapped[int] = mapped_column(primary_key=True)
bs: Mapped[List["B"]] = relationship(back_populates="a")
blist: Mapped[List["B"]] = relationship(back_populates="alist")
class B(Base):
__tablename__ = 'b'
id: Mapped[int] = mapped_column(primary_key=True)
a_id: Mapped[int] = mapped_column(ForeignKey("a.id"))
a: Mapped[A] = relationship(back_populates="bs")
alist: Mapped[List["A"]] = relationship(back_populates="blist")
engine = sqlalchemy.create_engine("sqlite+pysqlite:///:memory:", echo=True)
Base.metadata.create_all(engine)
with Session(engine) as session:
a1 = A()
a2 = A()
a3 = A()
session.add_all([a1, a2, a3])
b1 = B(
a = a1,
)
session.add(b1)
# b1.alist.append(a2) # It raises `AttributeError` because b1.alist is None.
sessionmit()