Section 4.3. A Simple Form to Add Bookmark


4.3. A Simple Form to Add Bookmark

TurboGears has lots of tools to help you build, validate, and process form data. There's a web-based data editing tool in the TurboGears toolbox, and even an experimental FastData class to automate form creation for your model classes.

We cover each of these tools, but for now let's create a new method to our controller to add new bookmarks and feed data to it from a simple web form. Rather than do this all in one big step, let's start by creating a save_bookmark method in our controller that adds a predefined bookmark to the database. We set up some variables, and then create a new Bookmark object with the exact same syntax we used earlier in the chapter when we created our first bookmark through tg-admin shell.

By now, the code to do this should look familiar to you:

   @expose()    def save_bookmark(self):        name="Blue Sky on Mars"        link="http://blueskyonmars.com"        description="Another not so random link."        Bookmark(name=name, link=link, description=description)        raise redirect("/list")


This method sets up a few variables, and then creates a new Bookmark object using the exact same syntax we used earlier in the chapter when we created our first bookmark through tg-admin shell. When our new record is added to the database, the user will be sent the results of the /list page.

After you add this method, you can check to see that this works by browsing to http://localhost:8080/save_bookmark, and you should see the new bookmark in the list.

Of course, we don't really want to hard-code bookmarks to be added, so we can adjust the code to do something like this:

   @expose(template="bookmarker.templates.add")    def save_bookmark(self, name, link, description):        b=Bookmark(name=name, link=link, description=description)        raise redirect("/list")


This saves a new bookmark into the database, and then redirects the user to the standard list view. But now we need to get the name, link, and description variables from somewhere. Remember from Chapter 3 that CherryPy turns HTTP Post names and values directly into named parameters that will be passed into your exposed object? So, all you need to do is create a form that submits a name, link, and description to the /save_bookmark URL and everything will work.

You can copy list.kid to form.kid and edit the body to add a form. Here's the basic HTML you need in the body of form.kid:

<body> <form NAME="Add Bookmark" METHOD="post"ACTION="/save_bookmark">    <p>Name: <input name="name"></input></p>    <p>Link: <input name="link"></input></p>    <p>Description:<textarea name="description" rows="4" cols="30"></textarea></p>    <p><input type="submit" value="submit"></input></p> </form> </body>


This form submits its contents to the server, and CherryPy calls save_bookmark with the form inputs as named parameters, and save_bookmark adds the bookmark to the database and then redirects the user to /list.

To publish form.kid, we need one final step. We add a new method to our controller that looks like this:

    @expose(template="bookmarker.templates.form")     def bookmark(self):         return dict()


Now, if you browse to http://localhost:8080/bookmark, you'll get a form, and when you fill out that form, a new bookmark will be added to the database.

That's about all it takes to build a basic user input mechanism with TurboGears. Of course, there's a lot more that could be done. Our form and list pages aren't attractive, so some HTML/CSS magic would help a lot. But more important, there's no code to edit existing forms, delete unwanted bookmarks, or handle data validation. We cover all of that in the next chapter.

Why raise redirect?

At first glance, raising an exception to redirect the user to a new URL seems a bit odd. After all, aren't exceptions supposed to indicate errors in the program?

It turns out that exceptions aren't always about errors. In fact, Python has an Exception base class and another base class for errors (StandardError). An exception really just signals a change in control flow. Python's iterators take advantage of this by raising StopIteration when the iterator is exhausted.

What makes raise redirect nice is that it's an unambiguous signal that the code that follows is not going to execute. After you've stated you want to redirect the user, further processing doesn't make sense. If redirect was a normal function call, it would be possible to call it and then proceed to produce output that you expect to go to the browser, which is confusing. raise redirect neatly eliminates the possibility.





Rapid Web Applications with TurboGears(c) Using Python to Create Ajax-Powered Sites
Rapid Web Applications with TurboGears: Using Python to Create Ajax-Powered Sites
ISBN: 0132433885
EAN: 2147483647
Year: 2006
Pages: 202

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net