There are a lot of cases when we want to track time when an entity was created or updated. Here is a simple recipe to make some or all of your SQLAlchemy entities auto-timestamping.
To achieve this, we will provide a mixin class.
Prerequisutes:
from datetime import datetime
from sqlalchemy import Column, DateTime, event
The mixin class:
class TimeStampMixin(object):
""" Timestamping mixin
"""
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow)
@staticmethod
def _updated_at(mapper, connection, target):
target.updated_at = datetime.utcnow()
@classmethod
def __declare_last__(cls):
event.listen(cls, 'before_update', cls._updated_at)
This mixin class adds two columns, 'created_at' and 'updated_at', they are initialized with current timestamp.
A static method `_updated_at` just updates the `updated_at` field for the `target` instance it receives.
But the real magic is done in `__declare_last__` method. According to SQLAlchemy docs (see http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative.html#declare-last) it gets called after the mapper is configured. The reason is that we cannot set a listener for an unmapped class, and mixin itself will never be mapped. We could add listeners for each entity directly, but we want some magic.
So, this method adds a listener for `before_update` event for each derived class!
And finally,
from sqlalchemy.ext.declarative import declarative_base
class Base(TimeStampMixin):
pass
Base = declarative_base(cls=Base)
Just derive all your model entities from this custom Base class - and magic is here.
No comments:
Post a Comment