在SQLAlchemy声明性模型对象上进行Active Record-like验证
项目描述
简介
SAValidation简化了在SQLAlchemy声明性模型对象上进行Active Record-like验证的过程。
您可以使用 easy_install savalidation==dev 安装savalidation的开发版本。
主页目前是GitHub仓库。
使用示例
以下是从examples.py文件中的一个片段
from datetime import datetime
import formencode
import sqlalchemy as sa
import sqlalchemy.ext.declarative as sadec
import sqlalchemy.sql as sasql
import sqlalchemy.orm as saorm
from savalidation import ValidationMixin, watch_session
import savalidation.validators as val
engine = sa.create_engine('sqlite://')
#engine.echo = True
meta = sa.MetaData()
Base = sadec.declarative_base(metadata=meta)
Session = saorm.scoped_session(
saorm.sessionmaker(
bind=engine,
autoflush=False
)
)
sess = Session
class Family(Base, ValidationMixin):
__tablename__ = 'families'
# SA COLUMNS
id = sa.Column(sa.Integer, primary_key=True)
createdts = sa.Column(sa.DateTime, nullable=False, default=datetime.now, server_default=sasql.text('CURRENT_TIMESTAMP'))
updatedts = sa.Column(sa.DateTime, onupdate=datetime.now)
name = sa.Column(sa.Unicode(75), nullable=False, unique=True)
reg_num = sa.Column(sa.Integer, nullable=False, unique=True)
status = sa.Column(sa.Unicode(15), nullable=False, default=u'active', server_default=u'active')
# VALIDATION
STATUS_CHOICES = (
('active', 'Active'),
('inactive', 'Inactive'),
('moved', 'Moved'),
)
# will validate nullability and string types
val.validates_constraints()
val.validates_one_of('status', [k for k, v in STATUS_CHOICES])
#OTHER
def __str__(self):
return '<Family id=%s, name=%s>' % (self.id, self.name)
class Person(Base, ValidationMixin):
__tablename__ = 'people'
id = sa.Column(sa.Integer, primary_key=True)
createdts = sa.Column(sa.DateTime, nullable=False, server_default=sasql.text('CURRENT_TIMESTAMP'))
updatedts = sa.Column(sa.DateTime, onupdate=datetime.now)
name_first = sa.Column(sa.Unicode(75), nullable=False)
name_last = sa.Column(sa.Unicode(75), nullable=False)
family_role = sa.Column(sa.Unicode(20), nullable=False)
nullable_but_required = sa.Column(sa.Unicode(5))
ROLE_CHOICES = (
('father', 'Father'),
('mother', 'Mother'),
('child', 'Child'),
)
val.validates_constraints(exclude='createdts')
val.validates_presence_of('nullable_but_required')
val.validates_choices('family_role', ROLE_CHOICES)
class ReverseConverter(formencode.api.FancyValidator):
def _to_python(self, value, state):
if not isinstance(value, basestring):
raise formencode.Invalid('Must be a string type', value, state)
# this reverse a string or list...yah, I know, it looks funny
return value[::-1]
validates_reverse = val.formencode_factory(ReverseConverter)
converts_reverse = val.formencode_factory(ReverseConverter, sv_convert=True)
class ConversionTester(Base, ValidationMixin):
__tablename__ = 'conversion_testers'
id = sa.Column(sa.Integer, primary_key=True)
val1 = sa.Column(sa.String(25))
val2 = sa.Column(sa.String(25))
val3 = sa.Column(sa.String(25))
val4 = sa.Column(sa.String(25))
validates_reverse('val1')
validates_reverse('val2', sv_convert=True)
converts_reverse('val3')
converts_reverse('val4', sv_convert=False)
在发行版的测试目录中可以找到更多示例。
安装 & 测试源
(这是其中一种方法,还有其他方法)
# create a virtualenv
# activate the virtualenv
$ pip install -e git+git://github.com/blazelibs/sqlalchemy-validation.git@master#egg=savalidation
$ pip install nose
$ cd src/savalidation/savalidation
$ nosetests
问题 & 评论
已知问题
在通过关系、默认或onupdate列参数等设置ORM映射对象属性时,验证执行时这些最终值可能不可用。
在某些情况下,可以在提交之前(flush之后)当这些值在ORM对象上可用时捕获这个问题。
不幸的是,在值违反数据库约束的情况下,这没有太大价值。在这种情况下,将抛出一个真正的数据库异常。
依赖关系
SQLAlchemy > 0.7.6
FormEncode
python-dateutil(用于日期/时间转换器)
Nose(如果您想运行测试)
致谢
本项目借鉴了以下代码和想法:
当前状态
代码本身似乎很稳定,但API可能在将来发生变化。
变更日志
0.4.1版本发布于2016-11-23
修复了包中列出的Python版本
修复了readme中指向Elixir项目的损坏链接
更新了CircleCI设置并添加了AppVeyor
0.4.0版本发布于2016-06-10
添加了对Python 3.4+的支持(感谢Jiří Bireš)
在Circle CI上设置了持续集成
通过CodeCov生成覆盖率报告
0.3.2版本发布于2016-04-20
验证数值列值的精度和刻度
0.3.1版本发布于2016-02-23
修复了与formencode的兼容性问题,支持formencode 1.2和1.3
0.3.0版本发布于2014-09-30
修复了 .validates_constraints() 与 Text 列类型相关的bug
watch_session() 现在不再需要,需要 SQLAlchemy >= 0.7.6
目前为beta质量:已经长时间在生产中使用,但尚未广泛使用
0.2.1版本发布于2013-05-15
修复了问题#6 - 调整所需的python-dateutil版本。
0.2.0版本发布于2012-10-24
本发布版包含一些 向后不兼容的变更。
内部API清理
重构以使用SQLAlchemy(SA)事件,我们现在兼容并要求SA >= 0.7
变更:如果使用SA < 0.7.6,则必须在创建会话之前为每个会话实例调用savalidation.watch_session(),如果savalidation模块在创建会话之前实例化。
变更:验证器API已更改。如果您创建了自定义验证器,您需要查看validators.py中的更改。
发送给验证器方法的Formencode状态对象已将“instance”属性更改为“entity”。
添加了before_flush()辅助函数来装饰实体实例方法
- 移除了after_flush验证。取而代之的是,可以使用before_insert/before_update事件进行验证。
现在可以使用before_insert/before_update事件来验证非空外键。
- 移除了对列的默认值和server_default值的验证支持(因为它需要after_flush验证)
值
- formencode模式现在只在每个类中创建一次,而不是每个实例,
提高了性能。
0.1.5版本发布于2011-06-11
修复了0.1.4版本,该版本未包含版本文件
0.1.4版本发布于2011-06-11
更改python-dateutil依赖关系,以支持< 2.0,2.x是为Python 3准备的
0.1.3版本发布于2011-05-19
更改SQLAlchemy要求,以安装最新版本的包< 0.7