The previous step showed how to do the basics: let ZPT do most of the work and apply lxml.html to shove values in.
Obviously the previous step was very hard-wired. In this step we make a base class for the form that starts to move some of the work out of the view and into a form. We won’t, in this step, introduce the concept of multiple fields with declarative validators. But we will follow some of the same jargon we’ll use later with FormEncode schemas.
Add a module for a BaseForm at t3/baseform.py:
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 | """Base class for KARL3 forms.
"""
from lxml.html import document_fromstring
from lxml.html import tostring
from time import time
class BaseForm:
submit_name = 'form.submitted'
max_age = 200
def __init__(self, request):
self.request = request
self.start_time = time()
@property
def is_submitted(self):
return self.request.POST.get('form.submitted', False)
def validate(self, fieldvalues):
"""Look at various fields and update values and errors"""
fielderrors = {}
for f in fieldvalues.keys():
fielderrors[f] = None
age = self.request.POST.get('age', False)
if age is False or age == '':
fielderrors['age'] = 'Age is required'
try:
if int(age) > self.max_age:
msg = 'Age must not be over %s' % self.max_age
fielderrors['age'] = msg
fieldvalues['age'] = age
except ValueError:
fielderrors['age'] = 'Age must be an integer'
fieldvalues['age'] = age
return fieldvalues, fielderrors
def render(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
|
The t3/views.py module gets a lot simpler:
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 | 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
static_view = static('templates/static')
def my_view(context, request):
layout = get_template('templates/layout.pt')
form = BaseForm(request)
fieldvalues = {'age': 40} # Set a default age
if form.is_submitted:
fieldvalues, fielderrors = form.validate(fieldvalues)
else:
fielderrors = {'age': False}
form_html = render_template(
'templates/myform.pt',
request=request,
fielderrors=fielderrors,
)
rendered_form = form.render(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 becomes more generic when grabbing errors:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <html xmlns:tal="http://xml.zope.org/namespaces/tal">
<form method="post" action="${request.url}">
<fieldset tal:define="error fielderrors['age']">
<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>
|