Google App Engine Webapp
import os
from google.appengine.ext.webapp import template
import cgi
import wsgiref.handlers

from google.appengine.api import users
from google.appengine.ext import webapp

class HomePage(webapp.RequestHandler):
    def get(self):
        template_file = 'index.html'
        template_values = {
            'greetings': greetings
        }

        path = os.path.join(os.path.dirname(__file__), template_file)
        self.response.out.write(template.render(path, template_values))

class Guessbook(webapp.RequestHandler):
    def post(self):
        template_file = 'index.html'
        template_values = {
            'greetings': 'Hello'
        }

        path = os.path.join(os.path.dirname(__file__), template_file)
        self.response.out.write(template.render(path, template_values))

def main():
    application = webapp.WSGIApplication(
                                       [('/', HomePage),
                                        ('/sign', Guestbook)],
                                       debug=True)
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
  main()
application = webapp.WSGIApplication(
                                     [('/', MainPage)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

Here is the template for the above code:

<html>
  <body>
    {% for greeting in greetings %}
      {% if greeting.author %}
        <b>{{ greeting.author.nickname }}</b> wrote:
      {% else %}
       An anonymous person wrote:
      {% endif %}
      <blockquote>{{ greeting.content|escape }}</blockquote>
    {% endfor %}

    <form action="/sign" method="post">
      <div><textarea name="content" rows="3" cols="60"></textarea></div>
      <div><input type="submit" value="Sign Guestbook"></div>
    </form>

    <a href="{{ url }}">{{ url_linktext }}</a>

  </body>
</html>

This code defines two request handler, MainPage, mapped to the root URL (/), and Guestbook, mapped to /sign. When a WSGIApplication receives a request, it creates an instance of the RequestHandler class associated with the URL path in the request. It then calls a method that corresponds with the HTTP action of the request, such as get() for a HTTP GET request. Inside the method, information about the request is available using self.request. Typically, the method sets properties on self.response to prepare the response, then returns.

The URL path in a mapping is a regular expression. Regular expression special characters must be escaped. The regular expression can contain regexp groupings to match parts of the URL. Patterns matched in groupings are passed to request handlers as arguments (look at the signature of the get() method):

class BrowseHandler(webapp.RequestHandler):
    def get(self, category, product_id):
        # Do something with category and product_id

# Map URLs like /browse/(category)/(product_id) to BrowseHandler.
application = webapp.WSGIApplication(
    [(r'/browse/(.*)/(.*)', BrowseHandler)],
    debug=True)

def main():
    run_wsgi_app(application)

Retrieving form data:

The request handler can access the request data using its request property. The request object provides a get() method that returns values for arguments parsed from the query and from POST data. The method takes the argument name as its first parameter. By default, get() returns the empty string ('') if the requested argument is not in the request. If the parameter default_value is specified, get() returns the value of that parameter instead of the empty string if the argument is not present. If the argument appears more than once in a request, by default get() returns the first occurrence. To get all occurrences of an argument that might appear more than once as a list (possibly empty), give get() the argument allow_multiple=True:

name = self.request.get("name")
subscribe_to_newsletter = self.request.get("subscribe", default_value="no")
favorite_foods = self.request.get("favorite_foods", allow_multiple=True)

For requests with body content that is not a set of CGI parameters, such as the body of an HTTP PUT request, the request object provides the attributes body and body_file. body is the body content as a byte string. body_file provides a file-like interface to the same data.

uploaded_file = self.request.body

Building the Response:

The request handler instance builds the response using its response property, which is initialized to an empty Response object by the application.

The response object's out property is a file-like object that can be used for writing the body of the response.

class MyHandler(webapp.RequestHandler):
  def get(self):
    self.response.out.write("<html><body><p>Hi there!</p></body></html>")

The out stream buffers all output in memory, then sends the final output when the handler returns. webapp does not support streaming data to the client. The clear() method erases the contents of the output buffer, leaving it empty.

If the data written to the output stream is a Unicode value, or if the response includes a Content-Type header that ends with ; charset=utf-8, webapp encodes the output as UTF-8. By default, the Content-Type header is text/html; charset=utf-8, including the encoding behavior. If the Content-Type is changed to have a different charset, webapp assumes the output is a byte string to be sent verbatim.

Redirects, Headers and Status Codes:

Normally, the response includes an HTTP status code of 200, meaning "OK." Specifically, code 200 indicates that the URI refers to a valid resource, and that resource is included in the output of the response. Different circumstances call for different error codes. For example, if there was an error condition internal to the server that prevented the output of the intended data, the server can return a code of 500, meaning "Server error."

The request handler provides an error(…) method that prepares an error response with the given error code. For example: self.error(500)

Another common use of status codes is to redirect the user's browser to a different URI. The redirection can be permanent, indicating the URI was once valid for the requested resource but all future requests for the resource should use the new URI. Or, the redirection can be temporary, indicating the requested URI is valid but the browser should request a different URI for now. A common technique for web applications is to use a temporary redirect in response to a successful form submission, preventing the user from accidentally using the browser's "back" button and re-submitting the form.

The request handler provides a redirect(…) method to prepare a redirect response. For example: self.redirect("/home")

redirect(…) takes the destination URI as its first parameter. By default, it establishes a temporary redirect. The optional argument permanent=True uses the permanent redirect code.

The request handler methods error(…) and redirect(…) change the HTTP status codes for the response. redirect(…) also uses an HTTP header to communicate the new URI to the client. The Response object provides methods for setting the status code and HTTP headers directly.

The response object's set_status(…) method changes the status code for the response. The method takes the numeric status code as its first parameter. An optional second parameter specifies a message to use instead of the default for the given status code.

The response object's headers property is a wsgiref.headers.Headers instance that represents the HTTP headers for the response. For information on how to set headers, see the wsgiref.headers documentation.

Instance Variables Inherited From WebOb Request:

remote_addr           // The remote user's IP address.
url                            // The full request URL.
path                         // The path of the URL, between the host name and the query parameters.
query_string            // The query parameters of the URL, everything after the first ?
headers                   // The request headers, a dictionary-like object. Keys are case-insensitive.
cookies                    // The cookie data from the request, a dictionary-like object.
class StatusImageHandler(webapp.RequestHandler):
  def get(self):
    img_data = get_status_image_for_current_user()
    self.response.headers["Content-Type"] = "image/png"
    self.response.headers.add_header("Expires", "Thu, 01 Dec 1994 16:00:00 GMT")
    self.response.out.write(img_data)

Miscellaneous

While the Request class is derived from the WebOb library, the Response class is not. However, the Response class includes several methods that behave similarly to the WebOb equivalent. (A future version of the API may use the WebOb class directly.)

Request is provided by the google.appengine.ext.webapp module. The Request class inherits from the WebOb Request class. Only some of the features of the WebOb Request class are discussed here. The Request class provided by webapp inherits from the WebOb Request class. webapp adds several new methods for accessing arguments submitted by web forms, and extends several default behaviors. Typically, the WSGIApplication instantiates a RequestHandler and initializes it with a Request object populated with a WSGI-compliant environment dictionary (environ).

In addition to the various get(), post(), put(), head(), options(), delete(), trace(), your class can override handle_exception():

handle_exception(exception, debug_mode)

to provide provide custom exception handling behavior.

from google.appengine.runtime import DeadlineExceededError

class MainPage(webapp.RequestHandler):
  def get(self):
    try:
      # Do stuff...

    except DeadlineExceededError:
      self.response.clear()
      self.response.set_status(500)
      self.response.out.write("This operation could not be completed in time...")

http://www.djangoproject.com/documentation/0.96/templates/
http://code.google.com/appengine/docs/webapp/requestclass.html
http://code.google.com/appengine/docs/webapp/requesthandlerclass.html

WebOb is an open source third-party library. See the WebOb documentation for a detailed API reference and examples.

You can bundle a framework of your choice with your application code by copying its code into your application directory. Popular frameworks for Python are: WSGI, DJango, CherryPy, Pylons, web.py, Cheetah, ClearSilver, Quixote, EZT.

page_revision: 13, last_edited: 1228866850|%e %b %Y, %H:%M %Z (%O ago)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License