Edgewall Software

Changes between Version 10 and Version 11 of GenshiTutorial


Ignore:
Timestamp:
Aug 29, 2007, 1:35:37 PM (17 years ago)
Author:
cmlenz
Comment:

Started validation part

Legend:

Unmodified
Added
Removed
Modified
  • GenshiTutorial

    v10 v11  
    351351
    352352Please note though that we're not performing ''any'' kind of validation on the input, and that's of course a bad thing. So let's add validation next.
     353
     354== Adding Form Validation ==
     355
     356We'll use [http://formencode.org/ FormEncode] to do the validation, but we'll keep it all fairly basic. Let's declare our form in a separate file, namely `geddit/form.py`, which will have the following content:
     357
     358{{{
     359#!python
     360from formencode import Schema, validators
     361
     362
     363class SubmissionForm(Schema):
     364    username = validators.UnicodeString(not_empty=True)
     365    url = validators.URL(not_empty=True, add_http=True, check_exists=False)
     366    title = validators.UnicodeString(not_empty=True)
     367}}}
     368
     369Now let's use that class in the `Root.submit()` method. First add the `from formencode import Invalid` and `from geddit.form import SubmissionForm` lines to the imports at the top of the file. Then, update the `submit()` method to match the following:
     370
     371{{{
     372#!python
     373    @cherrypy.expose
     374    def submit(self, cancel=False, **data):
     375        if cherrypy.request.method == 'POST':
     376            if cancel:
     377                raise cherrypy.HTTPRedirect('/')
     378            form = SubmissionForm()
     379            try:
     380                data = form.to_python(data)
     381                submission = Submission(**data)
     382                self.data.append(submission)
     383                raise cherrypy.HTTPRedirect('/')
     384            except Invalid, e:
     385                errors = e.unpack_errors()
     386        else:
     387            errors = {}
     388
     389        tmpl = loader.load('submit.html')
     390        stream = tmpl.generate(errors=errors)
     391        return stream.render('html', doctype='html')
     392}}}
     393
     394As you can tell, we now only add the submitted link to our database when validation is successful: all fields need to be filled out, and the `url` field needs to contain a valid URL. If the submission is valid, we proceed as before. If it is not valid, we render the submission form template again, passing it the dictionary of validation errors. Let's modify the `submit.html` template so that it displays those error messages:
     395
     396{{{
     397#!genshi
     398<html xmlns="http://www.w3.org/1999/xhtml"
     399      xmlns:py="http://genshi.edgewall.org/">
     400  <head>
     401    <title>Geddit: Submit new link</title>
     402  </head>
     403  <body>
     404    <h1>Geddit</h1>
     405
     406    <h2>Submit new link</h2>
     407    <form action="" method="post">
     408      <table summary=""><tr>
     409        <th><label for="username">Your name:</label></th>
     410        <td>
     411          <input type="text" id="username" name="username" />
     412          <span py:if="'username' in errors" class="error">${errors.username}</span>
     413        </td>
     414      </tr><tr>
     415        <th><label for="url">Link URL:</label></th>
     416        <td>
     417          <input type="text" id="url" name="url" />
     418          <span py:if="'url' in errors" class="error">${errors.url}</span>
     419        </td>
     420      </tr>
     421      <tr>
     422        <th><label for="title">Title:</label></th>
     423        <td>
     424          <input type="text" name="title" />
     425          <span py:if="'title' in errors" class="error">${errors.title}</span>
     426        </td>
     427      </tr></table>
     428      <div>
     429        <input type="submit" value="Submit" />
     430        <input type="submit" name="cancel" value="Cancel" />
     431      </div>
     432    </form>
     433
     434  </body>
     435</html>
     436}}}
     437
     438So now, if you submit the form without enterering a title, and having entered an invalid URL, you'd see something like the following:
     439
     440[[Image(tutorial02.png)]]
     441
     442But there's a problem here: Note how the input values have vanished from the form! We'd have to repopulate the form manually from the data submitted so far. We could do that by adding the required `value=""` attributes to th text fields in the template, but Genshi provides a more elegant way: the `HTMLFormFiller` steam filter. Given a dictionary of values, it can automatically populate HTML forms in the template output stream.
     443
     444To enable this functionality, first you'll need to add the import `from genshi.filters import HTMLFormFiller` to the `genshi/controller.py` file. Next, update the bottom lines of the `Root.submit()` method implementation so that they look as follows:
     445
     446{{{
     447#!python
     448        tmpl = loader.load('submit.html')
     449        stream = tmpl.generate(errors=errors) | HTMLFormFiller(data=data)
     450        return stream.render('html', doctype='html')
     451}}}
     452
     453Now, all entered values are preserved when validation errors occur.