SQLAlchemy中的属性自动更新

4 投票
1 回答
4002 浏览
提问于 2025-04-16 19:58

我有一个用sqlalchemy建立的模型,结构是这样的:

class Entry(Base):
    __tablename__ = 'entries'
    __table__ = Table('entries', Base.metadata,
            Column('id', Integer, primary_key=True, unique=True),
            Column('user_id', Integer, ForeignKey('users.id', onupdate="CASCADE", ondelete="RESTRICT")),
            Column('title', String(128)),
            Column('slug', String(128), index=True),
            Column('url', String(256), index=True),
            Column('entry', Text),
            Column('cached_entry', Text),
            Column('created', DateTime, server_default=text('current_timestamp')),
            Column('modified', DateTime, server_onupdate=text('current_timestamp')),
            Column('pubdate', DateTime),
            )

我希望的是,当我更新entry的时候,cached_entry也能重新生成。cached_entryentry的markdown解析版本。简单来说,我是在缓存markdown解析的结果,这样每次显示entry的时候就不用再解析一次了。我尝试过使用@hybrid_method,但是那似乎不行,因为它根本不存储在数据库里。我在Google AppEngine上搞定了这个,但我现在不知道怎么用SQLAlchemy做到同样的事情。

我真的不想在类里添加一个函数来替代模型中的名称,因为这样从应用的角度来看更难以管理,我不想不小心漏掉什么。

1 个回答

6

@hybrid_descriptor 确实是按照 这个链接 上描述的方式来实现的。你可以把数据库中对应的属性赋值给一个不同的名字。因为你在使用 __table__,所以可以用类似这样的方式:

class Entry(Base):
    __table__ = ...

    _entry = __table__.c.entry

    @hybrid_property
    def entry(self):
        return self._entry

    @entry.setter
    def entry(self, value):
        self._entry = value
        self.cached_entry = markdown(value)

另外一种方法是使用 before_insert 和 before_update 事件,在刷新数据时填充这个列。这种方法简单,但缺点是你得等到 flush() 才能看到效果。

我觉得最快的“设置”方式是使用 @validates:

from sqlalchemy.orm import validates

class Entry(Base):
    __table__ = ...

    @validates('entry')
    def _set_entry(self, key, value):
        self.cached_entry = markdown(value)
        return value

撰写回答