Working with POST Data from HTML Forms
The previous lab showed how to take a request from a client and return a response containing static HTML. This lab shows how you could write code to control how each response is generated, and act on data submitted from an HTML form.
4.3.1. How Do I Do That?
Write functions that take a Request object and work with it to generate a response. Set up a dictionary to map each available path in your web site to a function that will handle requests for that path. Use the Request.args dictionary to access data submitted from an HTML form. Example 4-3 shows a web server that generates one page containing an HTML form, and another page that processes the form and displays the results.
Example 4-3. formhandler.py
from twisted.web import http def renderHomePage(request): colors = 'red', 'blue', 'green' flavors = 'vanilla', 'chocolate', 'strawberry', 'coffee' request.write("""
Form Test
Your name:
What's your favorite color?
""") for color in colors: request.write( "%s
" % ( color, color.capitalize( ))) request.write("""
What kinds of ice cream do you like?
""") for flavor in flavors: request.write( "%s
" % ( flavor, flavor.capitalize( ))) request.write("""
""") request.finish( ) def handlePost(request): request.write("""Posted Form Datagg
Form Data
""") for key, values in request.args.items( ): request.write("
%s
" % key) request.write("
- ") for value in values: request.write("
- %s
- " % value) request.write("
") request.write(""" """) request.finish( ) class FunctionHandledRequest(http.Request): pageHandlers = { '/': renderHomePage, '/posthandler': handlePost, } def process(self): self.setHeader('Content-Type', 'text/html') if self.pageHandlers.has_key(self.path): handler = self.pageHandlers[self.path] handler(self) else: self.setResponseCode(http.NOT_FOUND) self.write("
Not Found
Sorry, no such page.") self.finish( ) class MyHttp(http.HTTPChannel): requestFactory = FunctionHandledRequest class MyHttpFactory(http.HTTPFactory): protocol = MyHttp if __name__ == "_ _main_ _": from twisted.internet import reactor reactor.listenTCP(8000, MyHttpFactory( )) reactor.run( )
Run formhandler.py. It will start a web server on port 8000. Go to http://localhost:8000/ and fill out the form on the home page. Figure 4-4 shows the home page with some fields already filled in.
Figure 4-4. Filling out the form generated by formhandler.py
When you click the Submit button, your browser will send the form data to the page formhandler using an HTTP POST request. When it receives the form data, formhandler will show you the fields and values that were submitted, as shown in Figure 4-5.
Figure 4-5. Displaying data submitted from a form
4.3.2. How Does That Work?
Example 4-3 defines two different functions for handling requests, renderHomePage and handlePost. FunctionHandledRequest is a subclass of Request with an attribute called pageHandlers that maps paths to functions. The process method looks at the path this particular request is using and tries to find a matching path in pageHandlers. If a match is found, the FunctionHandledRequest passes itself to the matching function, which is free to process the request however it likes; if no match is found, it generates a 404 "Not Found" response.
The renderHomePage function is set as the handler for /, the root page of the site. It generates an HTML form that will submit data to the page /formhandler. The handler function for /formhandler is handlePost, which responds with a page listing the posted data. handlePost iterates through the keys and values in Request args, which is a dictionary representing all the form data sent with the request.
|
An HTML form can have multiple fields with the same name. For example, the form in Example 4-3 lets you check off multiple checkboxes, all which have the name of a flavor. Unlike many other web frameworks, http.Request doesn't hide this from you: instead of a mapping each field name to a string, Request.args maps each field name to a list. If you know there's going to be one value for a particular field, just grab the first value from the list.