In this first step we make a view with a self-posting form, but no machinery at all. No validators, no majik. Instead, we show:
cd to the t3 directory, the one containing setup.py.
Edit setup.py and say that this package uses nose as its test runner. Do this by replacing the existing test_suite line with the following:
test_suite="nose.collector",
KARL3 uses nose as its test suite runner.
Make sure the tests still run. From the top t3 directory:
(t3)bash-3.2$ python ./setup.py test
running test
running egg_info
writing requirements to t3.egg-info/requires.txt
writing t3.egg-info/PKG-INFO
writing top-level names to t3.egg-info/top_level.txt
writing dependency_links to t3.egg-info/dependency_links.txt
writing entry points to t3.egg-info/entry_points.txt
reading manifest file 't3.egg-info/SOURCES.txt'
writing manifest file 't3.egg-info/SOURCES.txt'
running build_ext
test_my_view (t3.tests.ViewIntegrationTests) ... ok
test_my_view (t3.tests.ViewTests) ... ok
Ran 2 tests in 0.243s
OK
Add some error logging middleware in your t3.ini file:
[DEFAULT]
debug = true
[app:zodb]
use = egg:FeedsTool#app
reload_templates = true
debug_authorization = false
debug_notfound = false
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
pipeline =
egg:Paste#cgitb
egg:repoze.zodbconn#closer
egg:repoze.tm#tm
zodb
[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 6543
Run the server:
(t3)bash-3.2$ paster serve t3.ini --reload
Visit http://localhost:6543/ in your browser. You should see the colorful BFG intro screen.
To shorten the ZPT, let’s have a “theme”.
Create a t3/templates/layout.pt:
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 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
metal:define-macro="master">
<head>
<title>KARL3 Forms Demo</title>
<link href="${request.application_url}/static/default.css"
rel="stylesheet" type="text/css" />
<link href="${request.application_url}/static/t3.css"
rel="stylesheet" type="text/css" />
</head>
<body>
<div id="logo">
<h2><code>KARL3 Forms</code>, a <code>repoze.bfg</code> application</h2>
</div>
<div id="header">
<div id="menu">
</div>
</div>
<div id="wrapper">
<!-- start page -->
<div id="page">
<!-- start content -->
<div class="post">
<h1 class="title">Sample Form</h1>
<div metal:define-slot="content" id="content"/>
</div>
<!-- end content -->
<!-- start sidebar -->
<div id="sidebar">
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/add_feed.html">Add Feed</a>
</li>
</ul>
</div>
<!-- end sidebar -->
<div style="clear: both;"></div>
</div>
</div>
<!-- end sidebar -->
<div style="clear: both;"></div>
<div id="footer">
<p id="legal">
( c ) 2008. All Rights Reserved. Template design
by <a href="http://www.freecsstemplates.org/">Free CSS
Templates</a>.<br /> The form part of this view renders at
${elapsed} requests/sec.
</p>
</div>
</body>
</html>
|
Note
We include a spot in the footer to measure the performance of the form system part of the request.
This theme includes a new t3/templates/static/t3.css:
1 2 3 4 5 6 7 8 9 | .error {
margin-left: 3em;
color: yellow;
}
.required {
background-color: red;
padding-left: 0.4em;
}
|
Change t3/templates/mytemplate.pt to fill the slot:
1 2 3 4 5 6 7 8 9 10 11 12 | <div xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
metal:use-macro="layout.macros['master']">
<div metal:fill-slot="content">
${form_html}
</div>
</div>
|
We render the form separately from the page so we can use lxml.html to hack it. The form is in t3/templates/myform.pt:
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}" class="${formerror}">
<fieldset>
<label>Age <span class="required"> </span></label>
<input name="age"/>
<div tal:condition="fielderror" class="error">${fielderror}</div>
</fieldset>
<fieldset>
<input type="submit" name="form.submitted"/>
</fieldset>
</form>
</html>
|
The t3/views.py file does more work:
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 | 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 lxml.html import document_fromstring
from lxml.html import tostring
from time import time
static_view = static('templates/static')
def my_view(context, request):
layout = get_template('templates/layout.pt')
start = time()
fielderror = formerror = None
default_age = formfill_age = 40
max_age = 200
if request.POST.get('form.submitted', False):
# Form was submitted, do some validation
age = request.POST.get('age', False)
if age is False or age == '':
print 'Age is required'
fielderror = 'Age is required'
try:
if int(age) > max_age:
print '%s is over the max_age of %s' % (age, max_age)
fielderror = 'Age must not be over %s' % age
# Whether age is valid or not, shove it back into the form
formfill_age = age
except ValueError:
print 'Age is not an integer'
fielderror = 'Age must be an integer'
formfill_age = age
form_html = render_template(
'templates/myform.pt',
request=request,
formerror=formerror,
fielderror=fielderror,
)
# Merge in the value for the age, either from the default or from
# what they typed in.
form_tree = document_fromstring(form_html)
form = form_tree.forms[0]
form.fields['age'] = str(formfill_age)
merged_form_html = tostring(form)
elapsed = str(1 / (time() - start))[0:7]
return render_template_to_response(
'templates/mytemplate.pt',
request = request,
layout=layout,
form_html=merged_form_html,
elapsed=elapsed,
)
|
Go to http://localhost:6543/ in your browser and you should see the form.