views:

217

answers:

2

I'm fairly novice to FormAlchemy and it seems that I don't get something. I have a SQLAlchemy model defined like this:

...
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)
...

Then in my (Pylons) controller I create a FormAlchemy form like this:

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')])

The documentation says that "By default, NOT NULL columns are required. You can only add required-ness, not remove it.", but I want to allow non-NULL empty strings, which validators.required disallows. Is there something like blank=True, null=False in Django?

To be more precise, I want a custom validator like one below, to either allow empty strings with type=None or all values to be set non-NULL and non-empty:

# 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')

If possible, I'd like to refrain from monkey-patching formalchemy.validators.required or other kludges. I don't want to set nullable=True on model fields, because it doesn't seems to be proper solution too.

What's the correct way to validate form in such case? Thanks for any suggestions in advance.

+2  A: 

Can you explain why nullable=True would not be the solution?

To me it seems useless to store empty strings in the database and I would not encourage it. If there is no data than choose the more efficient type for the database.

Personally I think the Django solution in case of strings is wrong since it does not really support NULL in CharFields. If you want to store NULL in a CharField you will have to do it manually in the code.

WoLpH
Thanks for suggestion, maybe you're right. There are different opinions on this matter: http://stackoverflow.com/questions/265875/default-string-initialization-null-or-empty. Anyway, the answer is simple and not so fortunate — it's already existing ("legacy") database support. There's already quite a lot of code using that DB already and the convention is to store empty strings for "no value" and avoid NULLs.
drdaeman
+1  A: 

Finally found a (klugde, but seems this is the only sane choice) way to do this.

  fs.serial_number.validators.remove(formalchemy.validators.required)
  fs.mac.validators.remove(formalchemy.validators.required)

(Regarding my validator) Note, that FA will completely skip all validation when the value is None, because, by convention, it won't pass None to validators (except for validators.required, which is hard-coded). I've filed an enhancement request ticket trying to solve this: http://code.google.com/p/formalchemy/issues/detail?id=117

drdaeman