def addValidators(field, column, validators=None, getDBSes=None, model=None): if validators is None: validators = field.validators if not hasattr(field, 'extattrs'): field.extattrs = {} extattrs = field.extattrs if column.nullable: validators.append(Optional()) elif not isinstance(column.type, types.Boolean): validators.append(InputRequired()) field.label = RequiredLabel(field.label.field_id, field.label.text) if column.unique and getDBSes is not None and model is not None: validators.append(Unique(getDBSes, model, column)) if isinstance(column.type, types.String) and column.type.length: validators.append(Length(max=column.type.length)) extattrs['maxlength'] = column.type.length elif isinstance(column.type, (types.Integer, types.SmallInteger, types.BigInteger, types.Float, types.Numeric)): extattrs['maxlength'] = 15 if not any(isinstance(v, NumberRange) for v in validators): # arbitary decision to forbid negatives unless otherwise allowed # TODO support HTML5 input[number] max and min? validators.append(NumberRange(min=0)) for vtor in validators: flags = getattr(vtor, 'field_flags', ()) for flag in flags: setattr(field.flags, flag, True)
class SignupForm(Form): username = StringField('Username', validators=[ DataRequired(), Regexp('^[A-Za-z0-9\-_]+$', message='Only alphabets, numbers, hyphen, and underscore are allowed.'), Unique(lambda: db.session, User, User.username) ]) password = PasswordField('Password', validators=[DataRequired()]) password_confirmation = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password', 'Password confirmation is different from password.') ])
class UserForm(Form): username = TextField('Username', [ Length(min=4, max=25), Unique(lambda: self.sess, User, User.username) ])
def convert(self, model, mapper, prop, field_args, db_session=None): if not hasattr(prop, 'columns') and not hasattr(prop, 'direction'): return elif not hasattr(prop, 'direction') and len(prop.columns) != 1: raise TypeError('Do not know how to convert multiple-column ' + 'properties currently') kwargs = { 'validators': [], 'filters': [], 'default': None, } converter = None column = None if not hasattr(prop, 'direction'): column = prop.columns[0] # Support sqlalchemy.schema.ColumnDefault, so users can benefit # from setting defaults for fields, e.g.: # field = Column(DateTimeField, default=datetime.utcnow) default = getattr(column, 'default', None) if default is not None: # Only actually change default if it has an attribute named # 'arg' that's callable. callable_default = getattr(default, 'arg', None) if callable_default and callable(callable_default): default = callable_default(None) kwargs['default'] = default if column.nullable: kwargs['validators'].append(validators.Optional()) else: kwargs['validators'].append(validators.Required()) if db_session and column.unique: kwargs['validators'].append( Unique(lambda: db_session, model, column)) if self.use_mro: types = inspect.getmro(type(column.type)) else: types = [type(column.type)] for col_type in types: type_string = '%s.%s' % (col_type.__module__, col_type.__name__) if type_string.startswith('sqlalchemy'): type_string = type_string[11:] if type_string in self.converters: converter = self.converters[type_string] break else: for col_type in types: if col_type.__name__ in self.converters: converter = self.converters[col_type.__name__] break else: return if db_session and hasattr(prop, 'direction'): foreign_model = prop.mapper.class_ nullable = True for pair in prop.local_remote_pairs: if not pair[0].nullable: nullable = False kwargs.update({ 'allow_blank': nullable, 'query_factory': lambda: db_session.query(foreign_model).all() }) converter = self.converters[prop.direction.name] if field_args: kwargs.update(field_args) return converter(model=model, mapper=mapper, prop=prop, column=column, field_args=kwargs)
class CategoryForm(Form): name = StringField('Name', validators=[DataRequired()]) slug = SlugField('name', label='Slug', validators=[ Regexp('^[0-9a-z\-]+$', message='Only lowercase alphabets, numbers, and hyphen are allowed.'), Unique(lambda: db.session, Category, Category.slug) ])