Я работаю над проектом, который требует общей настройки для каждой создаваемой модели. На сегодняшний день я выполнил большую часть работы с помощью наследования моделей. Вот мой блок кода, чтобы дать вам лучшее представление:
app.core.dba.mixins:
class AuditExtension(MapperExtension):
"""
AuditExtension enforces the audit column values, and ensures any interaction with
SQLAlchemy cannot override the values
"""
def before_insert(self, mapper, connection, instance):
instance.created_dt = datetime.utcnow()
instance.created_by = audit_session_user()
instance.updated_dt = datetime.utcnow()
instance.updated_by = audit_session_user()
def before_update(self, mapper, connection, instance):
# Never update the created columns
instance.created_dt = instance.created_dt
instance.created_by = instance.created_by
instance.updated_dt = datetime.utcnow()
instance.updated_by = audit_session_user()
class AuditColumns(object):
""" Generate the column schema for simple table level auditing. """
created_dt = Column(DateTime,
default=datetime.utcnow(),
nullable=False)
created_by = Column(String(64),
#ForeignKey('operators.username', ondelete="RESTRICT"),
nullable=False)
updated_dt = Column(DateTime,
default=datetime.utcnow(),
nullable=False,
onupdate=datetime.utcnow())
updated_by = Column(String(64),
#ForeignKey('operators.username', ondelete="RESTRICT"),
nullable=False)
__mapper_args__ = {
'extension': AuditExtension()}
Затем мои модели наследуют AuditColumns:
class ObjectTypes(Base, AuditColumns):
__tablename__ = 'object_types'
id = Column(BigInteger, primary_key=True)
name = Column(String, nullable=False, unique=True)
def __repr__(self):
return self.name
Моя проблема в том; мое решение для форсирования данных аудита работает до тех пор, пока операция содержится в приложении фляги и SQLAlchemy - это не мешает любому, у кого есть доступ к базе данных, обновлять значения.
Поэтому теперь мне нужно реализовать триггер для каждой модели, наследующей AuditColumns. Я нашел этот пост Sqlalchemy mixins/и прослушиватель событий - и он описывает метод для before_insert /update (который у меня раньше работал), но не для «after_create».
Теперь я добавил это в свой код файла миксинов (сразу после кода аудита выше:
trig_ddl = DDL("""
CREATE TRIGGER tr_audit_columns BEFORE INSERT OR UPDATE
ON test_table
FOR EACH ROW EXECUTE PROCEDURE
ss_test();
""")
event.listen(AuditColumns, 'after_create', trig_ddl)
Однако, когда я запускаю тестовый пример:
Base.metadata.drop_all(db.get_engine(app))
Base.metadata.create_all(db.get_engine(app))
Я получаю следующую ошибку:
File "D:\Devel\flask-projects\sc2\app\core\dba\mixins.py", line 59, in <module>
event.listen(AuditColumns, 'after_create', trig_ddl)
File "D:\Devel\flask-projects\env\lib\site-packages\sqlalchemy\event.py", line 43, in listen
(identifier, target))
sqlalchemy.exc.InvalidRequestError: No such event 'after_create' for target '<class 'app.core.dba.mixins.AuditColumns'>'
Я предполагаю, что это потому, что это еще не стол; но как бы я глобально определил прослушиватель событий для создания таблицы, который будет выполнять этот тип команды?
Я знаю, что мне нужно сделать триг_ддл динамическим (что, я не думаю, будет слишком сложно, но мне, по крайней мере, нужно выяснить глобальный элемент этого).
По сути, я не хочу, чтобы людям приходилось вручную прописывать в каждой модели это событие, когда оно явно привязано к этим столбцам аудита.
Любой толчок в правильном направлении был бы замечательным.