sqlalchemy的有限状态机字段

sqlalchemy-fsm的Python项目详细描述


PyPI versionBuild StatusMaintainabilityTest Coverage

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:

  1. <SqlAlchemy table class>.method()-返回可用于查询数据库的sqlalchemy筛选条件(例如session.query(BlogPost).filter(BlogPost.published())
  2. <SqlAlchemy table class>.method.is_(<bool>)-与<SqlAlchemy table class>.method() == <bool>
  3. 相同
  4. <SqlAlchemy record>.method()-返回布尔值,该值指示此特定记录是否处于该方法的目标状态()(例如if not blog.published():
  5. <SqlAlchemy record>.method.set(*args, **kwargs)-将记录对象的状态更改为转换的目标状态(如果无法更改,则引发异常)
  6. <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参数到transitionconditions必须是函数列表 只需要一个参数,模型实例。函数必须返回 TrueFalse或计算结果为TrueFalse的值。如果全部 函数返回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_changeafter_state_change。 在状态生命周期的预期点。

您可以通过的标准sqlalchemy接口订阅事件侦听器 listens_forlisten

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有何不同?

  • 无法从转换修饰函数中提交数据
  • 不支持条件函数的参数

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java找不到'com'的版本。谷歌。密码findbugs:jsr305'   java中的文件输入和输出   java如何在eclipse类路径中为jar文件赋予优先级?   java如何使用Ant自动重命名输出apk文件?   java在JavaFX画布中访问GraphicsContext中的元素   java Libgdx GWT WebSocket对象序列化   如何使用Java8流和lambda迭代和处理其值为元素列表的映射的值   java验证来自控制台的用户输入。命令是否有效等   windows server 2008 r2 Java运行时。exec执行不正确   java Openshift监控弹簧,显示吊舱   java一些谷歌搜索结果被复制   java无法通过Apache Camel访问外部HTTP服务   多线程一个简单的java多线程   java BigQuery/Gcp数据传输到Amazon S3   java我可以用子接口重新编译公共API并保持二进制兼容性吗?   javajavax。命名。NameNotFoundException:MyBean#找不到MyBean   java如何从akka参与者抛出异常?   Java流收集器。toMap值是一个集合