在FormAlchemy中不要求非NULL字段(允许空字符串)
我对FormAlchemy还比较陌生,似乎有些地方没弄明白。我定义了一个SQLAlchemy模型,代码如下:
...
class Device(meta.Base):
__tablename__ = 'devices'
id = sa.Column('id_device', sa.types.Integer, primary_key=True)
serial_number = sa.Column('sn', sa.types.Unicode(length=20), nullable=False)
mac = sa.Column('mac', sa.types.Unicode(length=12), nullable=False)
ipv4 = sa.Column('ip', sa.types.Unicode(length=15), nullable=False)
type_id = sa.Column('type_id', sa.types.Integer,
sa.schema.ForeignKey('device_types.id'))
type = orm.relation(DeviceType, primaryjoin=type_id == DeviceType.id)
...
然后在我的(Pylons)控制器中,我这样创建了一个FormAlchemy表单:
c.device = model.meta.Session.query(model.Device).get(device_id)
fs = FieldSet(c.device, data=request.POST or None)
fs.configure(options=[fs.ipv4.label(u'IP').readonly(),
fs.type.label(u'Type').with_null_as((u'—', '')),
fs.serial_number.label(u'S/N'),
fs.mac.label(u'MAC')])
文档上说“默认情况下,NOT NULL列是必填的。你只能添加必填项,不能去掉它。”但我想允许非空的空字符串,而validators.required
是不允许的。有没有类似于Django中的blank=True, null=False
的设置呢?
更具体地说,我想要一个自定义的验证器,像下面这样,要么允许空字符串并设置type=None
,要么所有值都设置为非空且非空字符串:
# For use on fs.mac and fs.serial_number.
# I haven't tested this code yet.
def required_when_type_is_set(value, field):
type_is_set = field.parent.type.value is not None:
if value is None or (type_is_set and value.strip() = ''):
raise validators.ValidationError(u'Please enter a value')
如果可以的话,我希望不去修改formalchemy.validators.required
或其他临时解决方案。我也不想在模型字段上设置nullable=True
,因为这似乎也不是个合适的解决办法。
在这种情况下,正确的表单验证方法是什么呢?提前感谢任何建议。
4 个回答
我遇到的情况和这个完全一样,我经常需要为现有的数据库写接口,想用formalchemy,但最后不得不手动去掉“必填”的设置,因为我无法更改数据库。
你能解释一下为什么 nullable=True
可能不是解决办法吗?
在我看来,把空字符串存储在数据库里是没什么用的,我也不推荐这样做。如果没有数据的话,应该选择更有效的数据库类型。
我个人觉得在处理字符串时,Django 的解决方案是不太对的,因为它并不真正支持 CharFields 中的 NULL 值。如果你想在 CharField 中存储 NULL 值,就得在代码里手动处理。
最后找到了一种权宜之计,但似乎这是唯一合理的做法:
fs.serial_number.validators.remove(formalchemy.validators.required)
fs.mac.validators.remove(formalchemy.validators.required)
对于验证器函数,当值为 None
时,FA 会 完全 跳过所有的验证,因为按照惯例,它不会把 None
传给验证器(除了在设置了 validators.required
的情况下,这个是硬编码的)。我已经提交了一个增强请求,试图解决这个问题,具体可以查看这个 链接。