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