Какой хороший общий способ просмотра транзакций SQLAlchemy, в комплекте с аутентифицированным пользователем и т. Д.? - PullRequest
7 голосов
/ 07 декабря 2009

Я использую декларативное расширение SQLAlchemy. Я хотел бы, чтобы все изменения в журналах таблиц, включая изменения в отношениях многие-ко-многим (таблицы сопоставления). Каждая таблица должна иметь отдельную таблицу «log» с похожей схемой, но с дополнительными столбцами, указывающими, когда было внесено изменение, кто его сделал и т. Д.

Моя модель программирования будет выглядеть примерно так:

row.foo = 1
row.log_version(username, change_description, ...)

В идеале система не позволяла бы совершать транзакцию без вызова row.log_version.

Мысли

Ответы [ 2 ]

5 голосов
/ 08 декабря 2009

Слишком много вопросов в одном, поэтому те ответы, которые на все ответы не соответствуют формату ответов StackOverflow. Я постараюсь кратко описать подсказки, поэтому задайте им отдельный вопрос, если этого недостаточно.

Назначение пользователя и описания транзакции

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

Лучший способ - назначить пользователя сеансу. Это нормально, когда сессия создается для каждого веб-запроса (на самом деле, это лучший вариант для приложения с аутентификацией в любом случае), поскольку этот сеанс есть только у одного пользователя. Но прохождение описания таким способом не так хорошо.

И мое любимое решение состоит в том, чтобы расширить Session.commit() метод для принятия необязательного пользовательского (и, возможно, другой информации) параметра и присвоения ему текущей транзакции. Это самое гибкое решение, и оно хорошо подходит для прохождения описания. Обратите внимание, что информация привязана к одной транзакции и передается очевидным образом, когда транзакция закрыта.

Обнаружение изменений

Там есть sqlalchemy.org.attributes.instance_state(obj) содержит всю необходимую вам информацию. Наиболее полезным для вас является словарь state.committed_state, который содержит исходное состояние для измененных полей (включая отношения «многие ко многим!»). Существует также метод state.get_history() (или функция sqlalchemy.org.attributes.get_history()), возвращающий объект истории с методом has_changes() и свойствами added и deleted для нового и старого значения соответственно. В дальнейшем используйте state.manager.keys() (или state.manager.attributes) для получения списка всех полей.

Автоматическое сохранение изменений

SQLAlchemy поддерживает расширение mapper, которое может предоставлять хуки до и после обновления, вставки и удаления. Вы должны предоставить свое собственное расширение со всеми хуками до (вы не можете использовать после, так как состояние объектов изменяется при сбросе). Для декларативного расширения легко написать подкласс DeclarativeMeta, который добавляет расширение mapper для всех ваших моделей. Обратите внимание, что вы должны сбрасывать изменения дважды, если вы используете сопоставленные объекты для журнала, поскольку единица работы не учитывает объекты, созданные в хуках.

1 голос
/ 19 декабря 2009

У нас есть довольно полный рецепт "версий" на http://www.sqlalchemy.org/trac/wiki/UsageRecipes/LogVersions. Кажется, некоторые другие пользователи предоставили несколько вариантов. Механика «добавить строку, когда что-то меняется на уровне ORM» - все это есть.

В качестве альтернативы вы также можете перехватить на уровне выполнения, используя ConnectionProxy, поискать в документации по SQLA, как это использовать.

edit: управление версиями теперь входит в состав SQLA: http://docs.sqlalchemy.org/en/rel_0_8/orm/examples.html#versioned-objects

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...