Validators

Auto-assigned validators

By default WTForms-Alchemy ModelForm assigns the following validators:
  • InputRequired validator if column is not nullable and has no default value
  • DataRequired validator if column is not nullable, has no default value and is of type sqlalchemy.types.String
  • NumberRange validator if column if of type Integer, Float or Decimal and column info parameter has min or max arguments defined
  • DateRange validator if column is of type Date or DateTime and column info parameter has min or max arguments defined
  • TimeRange validator if column is of type Time and info parameter has min or max arguments defined
  • Unique validator if column has a unique index
  • Length validator for String/Unicode columns with max length
  • Optional validator for all nullable columns

Unique validator

WTForms-Alchemy automatically assigns unique validators for columns which have unique indexes defined. Unique validator raises ValidationError exception whenever a non-unique value for given column is assigned. Consider the following model/form definition. Notice how you need to define get_session() classmethod for your form. Unique validator uses this method for getting the appropriate SQLAlchemy session.

engine = create_engine('sqlite:///:memory:')

Base = declarative_base()

Session = sessionmaker(bind=engine)
session = Session()


class User(Base):
    __tablename__ = 'user'

    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.Unicode(100), nullable=False)
    email = sa.Column(
        sa.Unicode(255),
        nullable=False,
        unique=True
    )

class UserForm(ModelForm):
    class Meta:
        model = User

    @classmethod
    def get_session():
        # this method should return sqlalchemy session
        return session

Here UserForm would behave the same as the following form:

class UserForm(Form):
    name = TextField('Name', validators=[DataRequired(), Length(max=100)])
    email = TextField(
        'Email',
        validators=[
            DataRequired(),
            Length(max=255),
            Unique(User.email, get_session=lambda: session)
        ]
    )

If you are using Flask-SQLAlchemy or similar tool, which assigns session-bound query property to your declarative models, you don’t need to define the get_session() method. Simply use:

Unique(User.email)

Using unique validator with existing objects

When editing an existing object, WTForms-Alchemy must know the object currently edited to avoid raising a ValidationError. Here how to proceed to inform WTForms-Alchemy of this case. Example:

obj = MyModel.query.get(1)
form = MyForm(obj=obj)
form.populate_obj(obj)
form.validate()

WTForms-Alchemy will then understand to avoid the unique validation of the object with this same object.

Range validators

WTForms-Alchemy automatically assigns range validators based on column type and assigned column info min and max attributes.

In the following example we create a form for Event model where start_time can’t be set in the past.

class Event(Base):
    __tablename__ = 'event'

    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.Unicode(255))
    start_time = sa.Column(sa.DateTime, info={'min': datetime.now()})


class EventForm(ModelForm):
    class Meta:
        model = Event

Additional field validators

Example:

from wtforms.validators import Email

class User(Base):
    __tablename__ = 'user'

    name = sa.Column(sa.Unicode(100), primary_key=True, nullable=False)
    email = sa.Column(
        sa.Unicode(255),
        nullable=False,
        info={'validators': Email()}
    )

class UserForm(ModelForm):
    class Meta:
        model = User

Now the ‘email’ field of UserForm would have Email validator.

Overriding default validators

Sometimes you may want to override what class WTForms-Alchemy uses for email, number_range, length etc. validations. For all automatically assigned validators WTForms-Alchemy provides configuration options to override the default validator.

In the following example we set a custom Email validator for User class.

from sqlalchemy_utils import EmailType
from wtforms_components import Email


class User(Base):
    __tablename__ = 'user'

    name = sa.Column(sa.Unicode(100), primary_key=True, nullable=False)
    email = sa.Column(
        EmailType,
        nullable=False,
    )

class MyEmailValidator(Email):
    def __init__(self, message='My custom email error message'):
        Email.__init__(self, message=message)


class UserForm(ModelForm):
    class Meta:
        model = User
        email_validator = MyEmailValidator

If you don’t wish to subclass you can simply use functions / lambdas:

def email():
    return Email(message='My custom email error message')


class UserForm(ModelForm):
    class Meta:
        model = User
        email_validator = email

You can also override validators that take multiple arguments this way:

def length(min=None, max=None):
    return Length(min=min, max=max, message='Wrong length')


class UserForm(ModelForm):
    class Meta:
        model = User
        length_validator = length

Here is the full list of configuration options you can use to override default validators:

  • email_validator
  • length_validator
  • unique_validator
  • number_range_validator
  • date_range_validator
  • time_range_validator
  • optional_validator

Disabling validators

You can disable certain validators by assigning them as None. Let’s say you want to disable nullable columns having Optional validator. This can be achieved as follows:

class UserForm(ModelForm):
    class Meta:
        model = User
        optional_validator = None