Flask SQLAlchemy列约束为正整数。

15

如何使用Flask SQLAlchemy将列定义为正整数?

我希望答案看起来像这样:

class City(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    population = db.Column(db.Integer, positive=True)
    def __init__(self,population):
        self.population = population

然而,这个类定义会抛出一个错误,因为 SQLalchemy 不知道 'positive' 参数。

如果使用负值来实例化对象,我可以引发异常。但是,我不知道如何确保在更新后人口数量仍为正数。

谢谢任何帮助。

2个回答

31

不幸的是,在Python方面,SQLAlchemy 会尽力避免干扰;没有“特殊的SQLAlchemy”方式可以表达实例属性必须满足某些约束条件:

>>> class Foo(Base):
...     __tablename__ = 'foo'
...     id = Column(Integer, primary_key=True)
...     bar = Column(Integer)
...
>>> f = Foo()
>>> f.bar = "not a number!"
>>> f.bar
'not a number!'

如果您试图提交此对象,sqlalchey将抱怨,因为它不知道如何将提供的python值呈现为Integer列类型的SQL。

如果这不是您想要的,您只需要确保错误数据不会到达数据库,那么您需要一个Check约束。

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    bar = Column(Integer)
    __table_args__ = (
        CheckConstraint(bar >= 0, name='check_bar_positive'),
        {})

2
bar >= 0 should be called check_bar_non_negative. For check_bar_positive I would expect bar > 0 - Martin Thoma

2

我知道这已经过时了,但是说句实话,我的方法是使用 marshmallow(用于验证输入数据的序列化和反序列化以及数据验证库)来验证输入数据。

按照以下方式为您的模型创建架构:

from marshmallow import validate, fields, Schema

... 

class CitySchema(Schema):
    population = fields.Integer(validate=validate.Range(min=0, max=<your max value>))

当适合的时候,请使用您的模式对数据进行序列化/反序列化:

... 
city_data = {...} # your city's data (dict)
city_schema = CitySchema()
deserialized_city, validation_errors = city_schema.load(city_data) # validation done at deserialization
... 

使用序列化/反序列化库的优点在于可以在一个地方强制执行所有数据完整性规则。

1
尽管这是一个选项,我的看法是,它作为一种补充效果很好,但最好在数据层定义数据约束,以便通过其他手段不会泄漏出不良数据。例如,在验证上出现错误、编写手动创建数据的脚本、各种其他边缘情况等。 - digitalfoo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接