sqlalchemy的有限状态机字段
sqlalchemy-fsm的Python项目详细描述
sqlalchemy的有限状态机字段
sqlalchemy fsm为sqlalchemy模型添加声明性状态管理。 而不是向模型中添加一些状态字段,并管理其 值,可以使用fsmstate字段和mark model方法 使用transitiondecorator。你的方法会有副作用 国家的变化。
decorator还获取一个条件列表,所有条件都必须满足 在允许转换之前。
使用量
将fsmstate字段添加到模型中
fromsqlalchemy_fsmimportFSMField,transitionclassBlogPost(db.Model):state=db.Column(FSMField,nullable=False)
使用transitiondecorator注释模型方法
@transition(source='new',target='published')defpublished(self):""" This function may contain side-effects, like updating caches, notifying users, etc. The return value will be discarded. """
source参数接受状态列表或单个状态。 您可以使用*作为源,以允许从任何状态切换到target。
@transition-带注释的方法具有以下api:
- <SqlAlchemy table class>.method()-返回可用于查询数据库的sqlalchemy筛选条件(例如session.query(BlogPost).filter(BlogPost.published()))
- <SqlAlchemy table class>.method.is_(<bool>)-与<SqlAlchemy table class>.method() == <bool> 相同
- <SqlAlchemy record>.method()-返回布尔值,该值指示此特定记录是否处于该方法的目标状态()(例如if not blog.published():)
- <SqlAlchemy record>.method.set(*args, **kwargs)-将记录对象的状态更改为转换的目标状态(如果无法更改,则引发异常)
- <SqlAlchemy record>.method.can_proceed(*args, **kwargs)-如果调用.method.set(*args, **kwargs)(使用相同的*args, **kwargs)成功,则返回True。
您还可以使用None作为的源状态(例如,当state列为空时)。 但是,由于宗教原因,不可能创建以None为目标状态的转换。
转换也可用于类对象以创建一组处理程序 对于相同的目标状态。
@transition(target='published')classPublishHandler(object):@transition(source='new')defdo_one(self,instance,value):instance.side_effect="published from new"@transition(source='draft')defdo_two(self,instance,value):instance.side_effect="published from draft"classBlogPost(db.Model):...published=PublishHandler
转换仍然要通过调用模型的published.set()方法来调用。
还支持其他内联类语法:
@transition(target='published')classpublished(object):@transition(source='new')defdo_one(self,instance,value):instance.side_effect="published from new"@transition(source='draft')defdo_two(self,instance,value):instance.side_effect="published from draft"
如果调用published.set()成功而没有引发异常,则state字段 将被更改,但不会写入数据库。
defpublish_view(request,post_id):post=get_object__or_404(BlogPost,pk=post_id)ifnotpost.published.can_proceed():raiseHttp404;post.published.set()post.save()returnredirect('/')
如果给定的函数需要参数来验证,则需要包含它们 调用can_proceed时以及调用函数时包含它们时 正常情况下。假设publish.set()由于某种原因需要日期:
ifnotpost.published.can_proceed(the_date):raiseHttp404else:post.publish(the_date)
如果您的代码需要知道当前的状态模型,可以调用 主要功能函数。
ifpost.deleted():raiseHttp404
如果在更改状态之前需要满足某些条件,请使用 conditions参数到transition。conditions必须是函数列表 只需要一个参数,模型实例。函数必须返回 True或False或计算结果为True或False的值。如果全部 函数返回True,所有条件都视为满足并转换 是允许发生的。如果其中一个函数返回False,则转换 不会发生的。这些功能不应该有任何副作用。
您可以使用普通函数
defcan_publish(instance):# No publishing after 17 hoursifdatetime.datetime.now().hour>17:returnFalsereturnTrue
或模型方法
defcan_destroy(self):returnnotself.is_under_investigation()
使用如下条件:
@transition(source='new',target='published',conditions=[can_publish])defpublish(self):""" Side effects galore """@transition(source='*',target='destroyed',conditions=[can_destroy])defdestroy(self):""" Side effects galore """
您还可以使用fsm处理程序查询数据库。例如
session.query(BlogCls).filter(BlogCls.publish())
将返回其当前状态与“发布”的目标状态匹配的所有“博客”对象。
事件
sqlalchemy fsm与sqlalchemy的事件系统集成。 库公开两个触发的事件before_state_change和after_state_change。 在状态生命周期的预期点。
您可以通过的标准sqlalchemy接口订阅事件侦听器 listens_for或listen。
fromsqlalchemy.eventimportlistens_for@listens_for(Blog,'before_state_change')defon_state_change(instance,source,target):...
或
fromsqlalchemyimporteventdefon_state_change(instance,source,target):...event.listen(Blog,'after_state_change',on_state_change)
可以用sqlalchemy.event.remove()方法取消注册事件侦听器调用。
SqlAlchemy FSM与Django FSM有何不同?
- 无法从转换修饰函数中提交数据
- 不支持条件函数的参数