У меня есть таблица пользователей, и у них есть друзья, использующие отношения «многие ко многим» с таблицей ассоциаций. Итак, проблема в том, что когда я вставляю дружбу с user_id = 1 и friends_id = 2, отношение будет создано, но если я вставлю ту же самую дружбу user_id = 2 и friends_id = 1, она все равно будет создана. Я думаю, что проблема в моем UniqueConstraint моих моделях:
class FriendshipAssociation(Base):
__tablename__ = "users_friendship_associations"
__table_args__ = (
UniqueConstraint(
"user_id", "friend_id",
name="unique_users_friendship"
),
)
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), primary_key=True)
friend_id: Mapped[int] = mapped_column(ForeignKey("users.id"), primary_key=True)
status: Mapped[FriendshipAssociationStatus] = mapped_column(
Enum(FriendshipAssociationStatus),
default=FriendshipAssociationStatus.REQUESTED
)
requsted_by_user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
requsted_by_user: Mapped["User"] = relationship(foreign_keys=[requsted_by_user_id])
read: Mapped[bool] = mapped_column(Boolean, default=False, nullable=True)
def get_friend_id(self, user_id: int):
if self.user_id == user_id:
return self.friend_id
return self.user_id
def __repr__(self):
return f"{self.user_id=} {self.friend_id=} {self.status=} {self.requsted_by_user_id=}"
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
name: Mapped[str] = mapped_column(String(64))
username: Mapped[str] = mapped_column(String(32), nullable=True)
status: Mapped[UserStatus] = mapped_column(Enum(UserStatus), default=UserStatus.USER)
lang_code: Mapped[str | None] = mapped_column(String(35), nullable=True)
timezone: Mapped[str] = mapped_column(
String(50), default=DEFAULT_DB_USER_TIMEZONE, server_default=text(f"'{DEFAULT_DB_USER_TIMEZONE}'")
)
# permissions
can_write_admin_reports: Mapped[bool] = mapped_column(Boolean, default=True)
# relationships
admin_reports: Mapped[list["AdminReport"]] = relationship( # type: ignore
back_populates="user",
cascade="all, delete",
passive_deletes=True,
order_by="AdminReport.created_at.desc()"
)
played_games: Mapped[list["PlayedGameAssociation"]] = relationship( # type: ignore
back_populates="user"
)
friends: Mapped[list["User"]] = relationship( # type: ignore
secondary="users_friendship_associations",
primaryjoin=FriendshipAssociation.user_id == id,
secondaryjoin=FriendshipAssociation.friend_id == id,
lazy="selectin", back_populates="friends"
)
def __str__(self):
return f"{self.id}, {self.name}, {self.username}, {self.created_at}, {self.lang_code}, {self.timezone}"
def __repr__(self):
return f"{self.id}, {self.name}, {self.username}, {self.created_at}, {self.lang_code}, {self.timezone}"
Или, возможно, проблема в том, как я вставляю отношения:
async def create_requested_users_friendship(
session: AsyncSession, user_id: int, friend_id: int
) -> FriendshipAssociation:
try:
friendship = FriendshipAssociation(
user_id=user_id, friend_id=friend_id,
requsted_by_user_id=user_id
)
session.add(friendship)
await session.commit()
return friendship
except IntegrityError:
raise exceptions.DBUsersFriendhipAlreadyExistsError(f"FriendShip with {user_id=} and {friend_id=} already exists")