Подтвердить что ты не робот

SQLAlchemy, получить объект, не связанный с сеансом

Я пытаюсь получить коллекцию объектов из базы данных и передать ее другому процессу, который не связан с базой данных. Мой код похож на приведенный ниже, но я продолжаю получать:

sqlalchemy.exc.UnboundExecutionError: Instance <MyClass at 0x8db7fec> is not bound to a Session; attribute refresh operation cannot proceed

Когда я пытаюсь посмотреть на элементы моего списка вне метода get_list().

def get_list (obj):
    sesson = Session()
    lst = session.query(MyClass).all()
    session.close()
    return lst

Однако, если я использую это:

def get_list_bis (obj)
    session = Session()
    return session.query(MyClass).all()

Я могу использовать элементы, но беспокоюсь о состоянии сеанса, поскольку он не был закрыт.

Что мне здесь не хватает?

4b9b3361

Ответ 1

Если вы хотите, чтобы куча объектов, созданных путем запроса сеанса, была полезной вне сферы действия сеанса, вам необходимо удалить их для сеанс.

В вашем первом примере функции вам нужно будет добавить строку:

session.expunge_all()

перед

session.close()

В более общем плане, скажем, сессия не закрыта сразу, как в первом примере. Возможно, это сеанс, который хранится в течение всей продолжительности веб-запроса или что-то в этом роде. В таких случаях вы не хотите делать expunge_all. Вам нужно быть более хирургическим:

for item in lst:
    session.expunge(item)

Ответ 2

Это часто происходит из-за того, что объекты находятся в состоянии expired, срок действия объектов истекает, например, после фиксации, затем, когда такие объекты с истекшим сроком годности собираются использоваться, ORM пытается их refresh, но это не может быть сделано, когда объекты отсоединены от сеанса (например, потому что тот сеанс был закрыт). Этим поведением можно управлять, создавая сеанс с параметром expire_on_commit=False.

>>> from sqlalchemy import inspect
>>> insp = inspect(my_object)
>>> insp.expired
True  # then it will be refreshed...

Ответ 3

В моем случае я также сохранял связанную сущность, и этот рецепт помог мне обновить все экземпляры внутри сеанса, используя тот факт, что сеанс является итеративным:

map(session.refresh, iter(session))  # call refresh() on every instance

Это крайне неэффективно, но работает. Должно быть хорошо для юнит-тестов.

Последнее замечание: в Python3 map() является генератором и ничего не будет делать. Используйте реальные циклы списочных представлений