Код: Выделить всё
import sqlalchemy as sqal
client_group_association = sqal.Table(
"client_group_association",
Base.metadata,
sqal.Column("client_id", sqal.UUID, sqal.ForeignKey("client_info.id"), primary_key=True),
sqal.Column("group_id", sqal.UUID, sqal.ForeignKey("group_info.id"), primary_key=True)
)
class ClientInfo(Base):
"""Stores information of clients."""
__tablename__ = "client_info"
id: Mapped[uuid6.UUID] = mapped_column(sqal.UUID(as_uuid=True), primary_key=True,
insert_default=uuid6.uuid7())
name: Mapped[str] = mapped_column(sqal.String, nullable=False)
email: Mapped[str] = mapped_column(sqal.String, nullable=False)
phone: Mapped[str] = mapped_column(sqal.String, nullable=False)
age: Mapped[int] = mapped_column(sqal.Integer, nullable=False)
# Other unrelated fields
groups: Mapped[List[uuid6.UUID]] = mapped_column(UUIDList, nullable=True)
group_objs: Mapped[List["GroupInfo"]] = relationship(
secondary=client_group_association,
back_populates="client_objs"
)
__table_args__ = (sqal.UniqueConstraint('name', 'email', 'phone', name='_unique_client_details'),
sqal.ForeignKeyConstraint(['groups'], ['group_info.id'],
onupdate='CASCADE', ondelete='CASCADE'))
class GroupInfo(Base):
"""Stores information of groups."""
__tablename__ = "group_info"
id: Mapped[uuid6.UUID] = mapped_column(sqal.UUID(as_uuid=True), primary_key=True,
insert_default=uuid6.uuid7())
location: Mapped[Locations] = mapped_column(sqal.Enum(Locations), nullable=False)
members: Mapped[List[uuid6.UUID]] = mapped_column(UUIDList, nullable=True)
client_objs: Mapped[List["ClientInfo"]] = relationship(
secondary=client_group_association,
back_populates="group_objs"
)
__table_args__ = (sqal.UniqueConstraint('members', name='_unique_members'),
sqal.ForeignKeyConstraint(['members'], ['client_info.id'],
onupdate='CASCADE', ondelete='CASCADE'))
Код: Выделить всё
__LOCK: asyncio.Lock = asyncio.Lock()
__SQL_ENGINE: AsyncEngine = create_async_engine(f"sqlite+aiosqlite:///{DATABASE_NAME}")
@contextlib.asynccontextmanager
async def get_async_session(self, locked: bool = True) -> AsyncIterator[AsyncSession]:
Session = sessionmaker(bind=self.__SQL_ENGINE, class_=AsyncSession)
if locked:
async with self.__LOCK:
async with Session() as session:
yield session
else:
async with Session() as session:
yield session
< /code>
, казалось, сработало некоторое время; Я мог бы получить вложенные объекты, используя вложенные операторы SelectInload
Код: Выделить всё
stmt = select(ClientInfo).where(...)\
.limit(10)\
.options(selectinload(ClientInfo.group_objs)\
.selectinload(GroupInfo.client_objs)) # Force eager-loading
< /code>
Каждый раз, когда я хочу создать новую группу, теперь я сталкиваюсь с < /p>
sqlalchemy.exc.InvalidRequestError: Can't attach instance ; another instance with key (, (UUID('019634d4-1422-7a0e-9a21-96941acc10dd'),), None) is already present in this session.
Обратите внимание, что каждый раз, когда я хочу получить доступ к базе данных, я создаю новый сеанс. Это самая важная часть транзакции, потому что я ссылаюсь на объекты клиента через эти отношения в будущем.
Код: Выделить всё
group_info: GroupInfo = GroupInfo(id=uuid6.uuid7(),
location=self.location,
members=list(self.clients.keys()))
for client_info in self.clients.values():
group_info.client_objs.append(client_info)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
Код: Выделить всё
session.expunge(client_info)
session.expire(client_info)
# In constructor
self.group_objs_relationship = None
self.client_objs_relationship = None
# Later in the separate class
bot.client_object_relationship = group_info.client_objs # Nullability checked
bot.group_objs_relationship = group_info.client_objs[0].group_objs # Nullability checked
# When adding the new group:
try:
session.add(group_info)
except sqal.exc.InvalidRequestError:
print('Error raised when adding GroupInfo, trying alternate path!')
if bot.group_objs_relationship:
bot.group_objs_relationship.append(group_info)
else:
print('Sorry, could not add that.')
finally:
await session.commit()
Это работает для GroupInfo , но я понятия не имею, как добавить эти объекты ClientInfo в объект GroupInfo перед совершением, потому что удаление не работает в этом случае.
.>
Подробнее здесь: https://stackoverflow.com/questions/795 ... x7baada2f3