Let’s get rid of the hard-wired fields and validators and jump straight into FormEncode.schema.
This isn’t a complete jump: we’re still using our own baseform.validate method. We’ll get more FormEncode-onic in following steps.
Still, we can see from the request/second in the footer that this thing is pretty fast.
The``BaseForm`` at t3/baseform.py is now a subclass of Schema:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | """Base class for KARL3 forms.
"""
from lxml.html import document_fromstring
from lxml.html import tostring
from time import time
from formencode import Schema
from formencode import Invalid
class BaseForm(Schema):
submit_name = 'form.submitted'
allow_extra_fields = True
filter_extra_fields = True
def __init__(self):
Schema.__init__(self)
self.defaults = {}
for name, value in self.fields.items():
default = getattr(value, 'default', None)
if default is not None:
self.defaults[name] = value.default
def is_submitted(self, request):
self.start_time = time()
return request.POST.get('form.submitted', False)
def validate(self, fieldvalues):
fielderrors = {}
try:
fieldvalues = self.to_python(fieldvalues)
except Invalid, e:
fielderrors = e.error_dict
return fieldvalues, fielderrors
def merge(self, htmlstring, fieldvalues):
# Merge in field values, either from the default or from what
# they typed in.
form_tree = document_fromstring(htmlstring)
form = form_tree.forms[0]
for field_name, field_value in fieldvalues.items():
form.fields[field_name] = unicode(field_value)
merged_form_html = tostring(form)
# Record the elapsed time
self.elapsed = str(1 / (time() - self.start_time))[0:7]
return merged_form_html
def combine_dicts(self, dict1, dict2):
# We often have multiple sources for field values. For
# example, the default defined into the field versus the value
# typed into the request.params. Combine these, with the
# latter taking presence over the former.
fieldvalues = dict1
for key, value in dict2.items():
fieldvalues[key] = value
return fieldvalues
|
The t3/views.py module gets more realistic:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | from repoze.bfg.chameleon_zpt import render_template_to_response
from repoze.bfg.chameleon_zpt import get_template
from repoze.bfg.chameleon_zpt import render_template
from repoze.bfg.view import static
from baseform import BaseForm
from formencode import validators
from formencode import Invalid
static_view = static('templates/static')
# Define a form schema, make an instance
class MyAge(BaseForm):
age = validators.Int(not_empty=True, max=200, default=93)
myage = MyAge
def my_view(context, request):
layout = get_template('templates/layout.pt')
form = myage()
form_message = None
if form.is_submitted(request):
# We were submitted. Start by combining data from
# request.params and form.defaults.
fieldvalues = form.combine_dicts(form.defaults, request.params)
# Now validate
try:
fieldvalues = form.to_python(fieldvalues)
fielderrors = {}
# Go ahead and do the work to add content, etc.
form_message = "Saved the data."
except Invalid, e:
# Form data wasn't valid.
fielderrors = e.error_dict
else:
# Set default values and no errors
fieldvalues = form.defaults
fielderrors = {}
# Render the form and shove some default values in
form_html = render_template(
'templates/myform.pt',
request=request,
fielderrors=fielderrors,
form_message=form_message,
)
rendered_form = form.merge(form_html, fieldvalues)
return render_template_to_response(
'templates/mytemplate.pt',
request = request,
layout=layout,
form_html=rendered_form,
elapsed=form.elapsed,
)
|
The t3/templates/myform.pt form grows a place to show a form message:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <html xmlns:tal="http://xml.zope.org/namespaces/tal">
<form method="post" action="${request.url}">
<div tal:condition="form_message"
class="form_message">${form_message}</div>
<fieldset tal:define="error fielderrors['age']|None">
<label>Age <span class="required"> </span></label>
<input name="age"/>
<div tal:condition="error" class="error">${error}</div>
</fieldset>
<fieldset>
<input type="submit" name="form.submitted"/>
</fieldset>
</form>
</html>
|