Проблемы с scoped_session в sqlalchemy - как это работает?

Я не совсем уверен, как работает scoped_session, за исключением того, что он выглядит как обертка, которая скрывает несколько реальных сессий, сохраняя их отдельно для разных запросов. Это делает это с локальными потоками?

В любом случае проблема заключается в следующем:

S = elixir.session # = scoped_session(...)
f = Foo(bar=1)
S.add(f) # ERROR, f is already attached to session (different session)

Не знаю, как все закончилось в другой сессии, у меня не было проблем с этим раньше. В другом месте у меня есть код, который выглядит так же, но на самом деле работает. Как вы можете себе представить, я нахожу это очень запутанным.

Я просто ничего здесь не знаю, кажется, что f волшебным образом добавляется к сеансу в конструкторе, но у меня нет ссылок на сеанс, который он использует. Почему это закончится в другой сессии? Как я могу заставить это закончить в правильной сессии? Как это работает? Иногда кажется, что это работает, а иногда - нет.

Я определенно очень смущен.

2 ответа

Решение

Сеанс Scoped создает прокси-объект, который ведет реестр (по умолчанию) для объектов сеанса потока, созданных по требованию из переданной фабрики сеансов. При доступе к методу сеанса, например ScopedSession.add он находит сеанс, соответствующий текущему потоку, и возвращает add метод привязан к этой сессии. Активный сеанс можно удалить с помощью ScopedSession.remove() метод.

ScopedSession имеет несколько удобных методов, один из которых query_property это создает свойство, которое возвращает объект запроса, связанный с сессией области действия, в которой он был создан, и класс, к которому он был получен. Другой ScopedSession.mapper это добавляет по умолчанию __init__(**kwargs) конструктор и по умолчанию добавляет созданные объекты в сессию области действия, в которой был создан маппер. Это поведение может контролироваться save_on_init Ключевое слово аргумент в маппере. ScopedSession.mapper не рекомендуется из-за именно той проблемы, о которой идет речь. Это один из случаев, когда философия Python "явное лучше, чем неявное" действительно применима. К сожалению Эликсир по-прежнему использует по умолчанию ScopedSession.mapper,

Оказывается, elixir устанавливает save-on-init=True для созданных картографов. Это может быть отключено:

using_mapper_options(save_on_init=False)

Это решает проблему. Престижность к #sqlalchemy для того, чтобы выяснить, что происходило немедленно. Хотя мне все еще интересно, как на самом деле работает scoped_session, поэтому, если кто-то ответит на это, он получит кредит за ответ на вопрос.

Другие вопросы по тегам