sqlalchemy.orm.exc.DetachedInstanceError: Instance is not bound to a Session при удалении пользователя
Постоянно выдает ошибку "sqlalchemy.orm.exc.DetachedInstanceError: Instance <User at 0x2d790022f70> is not bound to a Session; attribute refresh operation cannot proceed (Background on this error at: https://sqlalche.me/e/20/bhk3)". Не знаю как от нее избавиться, при этом пользователь не удаляется из БД. Прикладываю код, который может помочь разобраться.
@router1.message(Form.waiting_for_deletion_number)
async def process_delete_input(message: types.Message, state: FSMContext):
if message.text == 'Назад':
await back(message, state)
return
phone_number = message.text.strip()
if not is_valid_phone_number(phone_number):
await message.answer("Номер телефона должен начинаться с '+'.")
return
user = await rq.get_user_by_number(phone_number)
if user:
tg_id = user.tg_id
fio = user.fio
user_deleted = await rq.delete_user_by_number(phone_number, tg_id, fio)
if user_deleted:
await message.answer(f"Сотрудник с номером {phone_number} успешно удален.")
else:
await message.answer(f"Сотрудник с номером {phone_number} не найден.")
await state.clear() # Завершаем состояние после удаления
Этот код я использую как хэндлер-админ. Для удаления из БД прописан код следующий код:
async def get_user_by_number(number: str):
async with async_session() as session:
async with session.begin():
result = await session.execute(select(User).filter(User.number == number))
return result.scalar_one_or_none()
async def delete_user_by_number(number: str, tg_id: int, fio: str):
async with async_session() as session:
async with session.begin():
# Извлекаем пользователя из базы данных
user_to_delete = await session.scalar(
select(User).where(User.tg_id == tg_id, User.number == number, User.fio == fio)
)
if user_to_delete:
# Обновляем экземпляр (если он был отсоединен)
await session.refresh(user_to_delete)
await session.delete(user_to_delete)
await session.commit()
return True
return False
Должно быть, чтобы в БД полностью удалялась строку по найденному номеру(т.е. все данные о пользователе)
DetachedInstanceError: Instance <User at 0x2d790022f70> is not bound to a Session; attribute refresh operation cannot proceed (Background on this error at: https://sqlalche.me/e/20/bhk3)
Traceback (most recent call last):
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\dispatcher.py", line 309, in _process_update
response = await self.feed_update(bot, update, **kwargs)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\dispatcher.py", line 158, in feed_update
response = await self.update.wrap_outer_middleware(
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\middlewares\error.py", line 25, in __call__
return await handler(event, data)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\middlewares\user_context.py", line 56, in __call__
return await handler(event, data)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\fsm\middleware.py", line 42, in __call__
return await handler(event, data)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\event\telegram.py", line 121, in trigger
return await wrapped_inner(event, kwargs)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\event\handler.py", line 43, in call
return await wrapped()
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\dispatcher.py", line 276, in _listen_update
return await self.propagate_event(update_type=update_type, event=event, **kwargs)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\router.py", line 146, in propagate_event
return await observer.wrap_outer_middleware(_wrapped, event=event, data=kwargs)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\router.py", line 141, in _wrapped
return await self._propagate_event(
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\router.py", line 174, in _propagate_event
response = await router.propagate_event(update_type=update_type, event=event, **kwargs)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\router.py", line 146, in propagate_event
return await observer.wrap_outer_middleware(_wrapped, event=event, data=kwargs)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\router.py", line 141, in _wrapped
return await self._propagate_event(
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\router.py", line 166, in _propagate_event
response = await observer.trigger(event, **kwargs)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\event\telegram.py", line 121, in trigger
return await wrapped_inner(event, kwargs)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\aiogram\dispatcher\event\handler.py", line 43, in call
return await wrapped()
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\app\handler_admin.py", line 92, in process_delete_input
tg_id = user.tg_id
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\sqlalchemy\orm\attributes.py", line 566, in __get__
return self.impl.get(state, dict_) # type: ignore[no-any-return]
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\sqlalchemy\orm\attributes.py", line 1086, in get
value = self._fire_loader_callables(state, key, passive)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\sqlalchemy\orm\attributes.py", line 1116, in _fire_loader_callables
return state._load_expired(state, passive)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\sqlalchemy\orm\state.py", line 803, in _load_expired
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\sqlalchemy\orm\attributes.py", line 1116, in _fire_loader_callables
return state._load_expired(state, passive)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\sqlalchemy\orm\attributes.py", line 1116, in _fire_loader_callables
return state._load_expired(state, passive)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\sqlalchemy\orm\state.py", line 803, in _load_expired
self.manager.expired_attribute_loader(self, toload, passive)
File "C:\Users\Evilitself\OneDrive\Рабочий стол\Тг бот\.venv\lib\site-packages\sqlalchemy\orm\loading.py", line 1603, in load_scalar_attributes
raise orm_exc.DetachedInstanceError(
sqlalchemy.orm.exc.DetachedInstanceError: Instance <User at 0x2d790022f70> is not bound to a Session; attribute refresh operation cannot proceed (Background on this error at: https://sqlalche.me/e/20/bhk3)
Ответы (1 шт):
Ошибка происходит в этом коде:
user = await rq.get_user_by_number(phone_number)
if user:
tg_id = user.tg_id
fio = user.fio
В этот момент сессия, которая была открыта в функции get_user_by_number
уже закончилась и объект user
уже не связан с БД. Вы можете отдавать из этой функции не ORM
-объект, а только нужные вам поля:
user = await rq.get_user_by_number(phone_number)
if user:
tg_id, fio = user
...
async def get_user_by_number(number: str):
async with async_session() as session:
async with session.begin():
result = await session.execute(select(User).filter(User.number == number))
user = result.scalar_one_or_none()
if user:
return user.tg_id, user.fio
else:
return None
Код получился не очень красивый, но идея, я думаю, должна быть понятна.