I have a form on my site that lets people choose a start date and a stop date. Then I show statistics for that date range. I wrote a FormEncode schema to verify that the start date is before the stop date.
The documentation on schema validators is fairly sparse, so I’m publishing this because it might help somebody else out.
Code
# This is in a file named formencodefun.py
from formencode import Schema
from formencode.validators import DateConverter, FancyValidator, Invalid
class DateCompare(FancyValidator):
messages = dict(invalid="Start date must be before stop date")
def validate_python(self, field_dict, state):
start_date = field_dict['start_date']
stop_date = field_dict['stop_date']
if start_date > stop_date:
msg = self.message('invalid', state)
raise Invalid(msg, field_dict, state,
error_dict=dict(stop_date=msg))
class MySchema(Schema):
start_date = DateConverter()
stop_date = DateConverter()
chained_validators = [DateCompare()]
Usage
>>> from formencodefun import MySchema
>>> s = MySchema()
>>> d1 = {'start_date':'11-02-2008', 'stop_date':'11-15-2008'}
>>> d2 = {'start_date':'11-15-2008', 'stop_date':'11-02-2008'}
>>> s.to_python(d1)
{'stop_date': datetime.date(2008, 11, 15), 'start_date': datetime.date(2008, 11, 2)}
>>> s.to_python(d2)
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
File "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/api.py", line 400, in to_python
value = tp(value, state)
File "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/schema.py", line 200, in _to_python
new = validator.to_python(new, state)
File "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/api.py", line 403, in to_python
vp(value, state)
File "formencodefun.py", line 18, in validate_python
error_dict=dict(stop_date=msg))
Invalid: Start date must be before stop date
How it works
Notice when I run s.to_python(d1), I get a dictionary back with the the values for start_date and stop_date replaced with datetime.date objects.
Then when I run my schema on d2, where the start_date is after the stop_date, my schema raises an Invalid exception. In a web framework like TurboGears, there is some exception handler that will catch that exception and take that error dictionary and redraw the form and print my error message.
Notice that the DateConverters first take my strings and turn them into datetime.date objects before the test in DateCompare. FormEncode runs the chained validators after it runs the individual validators.
In this case, I just want to make sure that the start date precedes the stop date. I have written other validators that add extra keys into the field dict or change the values, but I want to keep this example simple.
If the first DateConverters fail, then the chained validators never run:
>>> s.to_python({'start_date':'UNPARSEABLE', 'stop_date':'11-20-2008'})
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
File "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/api.py", line 400, in to_python
value = tp(value, state)
File "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/schema.py", line 197, in _to_python
error_dict=errors)
Invalid: start_date: Please enter the date in the form mm/dd/yyyy
When my DateCompare validator is run, I can be confident that the objects with the keys start_date and stop_date in the field_dict have already been converted to datetime.date objects.
In summary, FormEncode is awesome, but I have spent a lot of time beating my head against the wall trying to learn how to use it.
Add New Comment
Viewing 9 Comments
Thanks. Your comment is awaiting approval by a moderator.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Add New Comment