m2m relationship с одной таблицей
Есть 2 таблицы:
class User(Base):
__tablename__ = 'user'
id: Mapped[str_50] = mapped_column(primary_key=True, autoincrement=False)
username: Mapped[str_50] = mapped_column(nullable=True)
cash: Mapped[int] = mapped_column(nullable=False, server_default=text('0'))
is_admin: Mapped[bool] = mapped_column(nullable=False, server_default=text('false'))
at_create: Mapped[datetime.datetime] = mapped_column(nullable=False, server_default=func.now())
friends: Mapped[list['User']] = relationship(
back_populates='friends',
secondary='friend',
)
__table_args__ = (
CheckConstraint("cash >= 0", name="check_cash_positive"),
PrimaryKeyConstraint('id'),
)
class Friend(Base):
__tablename__ = 'friend'
sender_id: Mapped[str_50] = mapped_column(ForeignKey(column='user.id', ondelete='CASCADE'),
primary_key=True,
nullable=False)
addressee_id: Mapped[str_50] = mapped_column(ForeignKey(column='user.id', ondelete='CASCADE'),
primary_key=True,
nullable=False)
type_of: Mapped[Type_of_friendship] = mapped_column(nullable=False)
__table_args__ = (
PrimaryKeyConstraint('sender_id', 'addressee_id'),
)
Как вы видите, таблица User соединена сама с собой через таблицу Friend.
Мои запросы:
async def main():
from schemas.enum_models import Type_of_friendship
from schemas.pydantic_models import User_friends
async with async_engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
await conn.run_sync(Base.metadata.create_all)
async with async_session_factory() as session:
query = insert(User).values({'id': 1})
await session.execute(query)
query = insert(User).values({'id': 2})
await session.execute(query)
query = insert(Friend).values({'sender_id': 1,
'addressee_id': 2,
'type_of': Type_of_friendship.friend_request_from_me.value})
await session.execute(query)
query = select(User).options(selectinload(User.friends))
result = await session.execute(query)
print(User_friends.model_validate(result.scalars().all(), from_attributes=True))
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Появляется ошибка, как можно правильно написать m2m связь одной таблицы.
str_50 - VARCHAR(50)
Ответы (1 шт):
Автор решения: Мирон Климов
→ Ссылка
Нужно поменять:
friends: Mapped[list['User']] = relationship(
back_populates='friends',
secondary='friend',
)
На:
friends: Mapped[list['User']] = relationship(
back_populates='friends',
secondary='friend',
primaryjoin='user.c.id==friend.c.sender_id',
secondaryjoin='user.c.id==friend.c.sender_id',
)
нужно добавить primaryjoin и secondaryjoin в relationship