Python Sqlalchemy混合/和事件侦听器
我正在尝试两个新的东西,所以在两个简化和澄清的帮助是感激的Python Sqlalchemy混合/和事件侦听器,python,events,model,sqlalchemy,Python,Events,Model,Sqlalchemy,我正在尝试两个新的东西,所以在两个简化和澄清的帮助是感激的 from sqlalchemy.ext.declarative import declared_attr from sqlalchemy import Column, Float, event class TimeStampMixin(object): @declared_attr def __tablename__(cls): return cls.__name__.lower() cre
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy import Column, Float, event
class TimeStampMixin(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
created = Column(Float)
modified = Column(Float)
def __init__(self, created = None,
modified = None):
self.created = created
self.modified = modified
def create_time(mapper, connection, target):
target.created = time()
#def modified_time(mapper, connection, target):
# target.modified = time()
event.listen(TimeStampMixin, 'before_insert', create_time)
#event.listen(TimeStampMixin, 'before_update', modified_time)
所以我想创建一个可以应用于任何类的mixin:
class MyClass(TimeStampMixin, Base):
etc, etc, etc
此类继承了在创建时创建时间戳和在更新时创建/修改时间戳的功能
导入时出现以下错误:
raise exc.UnmappedClassError(class_)
sqlalchemy.orm.exc.UnmappedClassError: Class 'db.database.TimeStampMixin' is not mapped
aa我在这一点上被难住了。以下是我在插入事件之前收听
的方法:在timesmixin
中添加类方法,该方法注册当前类并处理设置创建时间
例如
这样,您可以:
轻松扩展和更改您收听的内容和注册的内容
重写某些类的create_time方法
明确哪些方法需要设置时间戳
您可以简单地使用它:
class MyMappedClass(TimeStampMixin, Base):
pass
MyMappedClass.register()
简单、清晰、无魔力,但仍能像您所希望的那样封装。您也可以这样做:
from sqlalchemy.orm.interfaces import MapperExtension
class BaseExtension(MapperExtension):
"""Base entension class for all entities """
def before_insert(self, mapper, connection, instance):
""" set the created_at """
instance.created = datetime.datetime.now()
def before_update(self, mapper, connection, instance):
""" set the updated_at """
instance.modified = datetime.datetime.now()
class TimeStampMixin(object):
id = Column(Integer, primary_key=True, autoincrement=True)
created = Column(DateTime())
modified = Column(DateTime())
__table_args__ = {
'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8'
}
__mapper_args__ = { 'extension': BaseExtension() }
并将您的类定义为:
class User(TimeStampMixin, Base):
将侦听器附加到class方法中,它将事件附加到子类
class TimeStampMixin(object):
@staticmethod
def create_time(mapper, connection, target):
target.created = time()
@classmethod
def __declare_last__(cls):
# get called after mappings are completed
# http://docs.sqlalchemy.org/en/rel_0_7/orm/extensions/declarative.html#declare-last
event.listen(cls, 'before_insert', cls.create_time)
现代SqlAlchemy中最好的方法是使用@listens\u for
装饰器和propagate=True
from datetime import datetime
from sqlalchemy import Column, Float
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.event import listens_for
class TimestampMixin():
@declared_attr
def created(cls):
return Column(DateTime(timezone=True))
@listens_for(TimeStampMixin, "init", propagate=True)
def timestamp_init(target, args, kwargs):
kwargs["created"] = datetime.utcnow()
你能公布实际的追踪结果吗?另外,您想用这一行完成什么:event.listen(TimeStampMixin,'before\u insert',create\u time)
?这是行不通的,因为TimeStampMixin
不是SQLAlchemy类(它是object的后代),所以SQLAlchemy无法知道它应该映射到哪个表。该错误是实际回溯的底部。我想要完成的就是我想要完成的,但是现在我又回到了这里,你也指出了,我看到sqlalchemy不会意识到它……但是就像我说的,尝试同时做两件新鲜的事情,我会错过很多。要记住的关键是sqlalchemy中没有什么是真正的魔法,所以,这就是为什么您只需要对它进行具体说明:)@blueblank,如果您感兴趣,staticmethod
只是Python中描述符的一个内置示例(这也是处理方法、类方法和属性的方式)。您可以阅读更多信息或看到具体的一个可能的缺点是,create\u time
不能被覆盖。既然register
是一个类方法,那么create\u time
就不能也是一个类方法吗?@mwhite这不是真的。如果在MyMappedClass
上定义create\u time
,register()
将使用它。Classmethod不会有任何不同,它总是绑定到register()
中的一个函数,所以即使是猴子修补类也不会改变它。啊,对了,谢谢。关于事件。侦听(…,lambda:cls.create_time)
呢?无论如何,MyMappedClass.create\u time()
不能调用super()来调用TimeStampMixin.create\u time()
?我想你可以。为了简单起见,我可能不想在继承方面做太多的工作。但是,是的,那会有用。与前面的答案有什么区别?@SergeBelov使用\uuu declare\uu last\uuuu
,我想这肯定是一个更好的答案-我不知道\uuu declare\u last\uuuuu
。如果有几个混音使用\uuu declare\u last\uuuu
,它们会被覆盖吗?如果单个模型包含多个mixin,则不起作用。请注意,MapperExtension自0.7以来一直存在。
from datetime import datetime
from sqlalchemy import Column, Float
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.event import listens_for
class TimestampMixin():
@declared_attr
def created(cls):
return Column(DateTime(timezone=True))
@listens_for(TimeStampMixin, "init", propagate=True)
def timestamp_init(target, args, kwargs):
kwargs["created"] = datetime.utcnow()