Handlers

Handlers are responsible for processing and responding to HTTP requests. Handlers are typically lightweight classes that glue the Models to the Templates. Handlers can be extended with Components and scaffolded.

Conventions

Handlers are named plural nouns in upper camel case (UpperCamelCase) from the models that they are associated with (for example: Pages, Users, Images, Bears, etc.). The are many cases where the plural convention doesn’t make sense, such as handlers that don’t have an associated model or handlers that span multiple models.

Each handler class should be in its own file under /app/handlers and the name of the file should be the underscored class name. For example, to create a handler to act on fuzzy bears, you would create the file /app/handlers/fuzzy_bears.py and inside of that define a class named FuzzyBears.

Anatomy of a Handler

class ferris.core.handler.Handler(*args, **kwargs)[source]

Handler allows grouping of common actions and provides them with automatic routing, reusable components, and automatic template discovery and rendering.

A handler is a class that inherits from Handler and contains special methods called actions.

Actions are normal instance methods that can be invoked via HTTP. Ferris takes care of automatically routing actions and generating URLS.

This section mostly focuses on actions and how to process and respond to requests. Other features are tied into handlers in various ways. Handler actions are exposed via the Routing system. Handlers can automatically discover and determine which template to use and render it. Handlers can process POST and JSON data and attach it to Forms. Handlers also allow you to break out common functionality using Components.

Requests

Actions can access the current request using self.request:

def list(self):
    return self.request.path

For more information on the request object see the webapp2 documentation on requests.

Data

Actions can also access the GET and POST variables using self.request.params:

def list(self):
    return self.request.params['text']

For just GET variables use self.request.GET, and for POST only use self.request.POST.

Parameters

Actions can also take various parameters on the URL as described in Routing:

def list(self, text, number):
    return text + str(number)

Context

Handler provides a bit of context about a request.

Handler.action = None

The current action

Handler.prefix = None

The current prefix

Handler.user = None

The current user as determined by google.appengine.api.users.get_current_user().

Handler.session[source]

Session object backed by an encrypted cookie and memcache.

Response

Actions can access the current response using self.response:

def list(self):
    self.response.write('hi')
    return self.response

For more information on the request object see the webapp2 documentation on responses.

Return Values

Actions can return a string and the string will become the body of the response:

def list(self):
    return 'Hi!'

Actions can return an integer and the will become the status of the response, in this case the response will be a 404 Not Found:

def list(self):
    return 404

Actions can return any webapp2.Response class, including self.response:

def list(self):
    self.response.content_type = 'text/json'
    self.response.text = '[0,1,2]'
    return self.response

Even if you return a string or integer, any changes to self.response are kept (except for the body or status, respectively):

def list(self):
    self.response.content_type = 'text/html'
    return '<h1>Hello!</h1>'

Returning nothing (None) will trigger the automatic template rendering unless auto_render is set to False:

def list(self):
    pass
    # Return nothing will cause /app/templates/handler/list.html to be loaded and rendered.

Redirection

Redirects can be generated using redirect() and uri():

@route
def auto(self):
    return self.redirect(self.uri(action='exterminate', who='everything'))

Template Rendering

Handler contains a bit of logic to make rendering templates easier. By default, returning None from an action will trigger automatic template rendering. You can easily pass data from the handler to the template and control how the handler finds its template.

Data

To provide data to the template use the get() and set() methods:

Handler.set(name=None, value=None, **kwargs)[source]

Set a variable in the template context. You can specify name and value or specify multiple values using kwargs.

Handler.get(name, default=None)[source]

Get a variable from the template context

For example:

def list(self):
    self.set(band="The Beatles")
    self.set({'members': ['John', 'Paul', 'George', 'Ringo']})
    self.get("band")  # Returns "The Beatles"

Determination

A Handler can automatically determine which template to use:

Handler._get_template_name()[source]

Generates a list of template names.

The template engine will try each template in the list until it finds one.

For non-prefixed actions, the return value is simply: [ "[handler]/[action].[ext]" ]. For prefixed actions, another entry is added to the list : [ "[handler]/[prefix_][action].[ext]" ]. This means that actions that are prefixed can fallback to using the non-prefixed template.

For example, the action Posts.json_list would try these templates:

posts/json_list.html
posts/list.html

If you’re not serving up html, you can change the extension:

Handler.template_ext = 'html'

The extension used by _get_template_name() when finding templates.

If you’d like to use a theme:

Handler.theme = None

Set to change the theme used by render_template

If you set template_name to the full path of the template that will be used instead of the result of _get_template_name(). This allows you to use templates from other actions and even other handlers:

Handler.template_name = None

If set, this will be used as the template to render instead of calling _get_template_name()

For example:

def list(self):
    self.template_name = 'shows/grid.html'

Rendering

By default, auto_render is enabled:

Handler.auto_render = True

If set to true, the handler will attempt to render the template determined by _get_template_name() if an action returns None.

Of course, you can also manually render a template:

Handler.render_template(template)[source]

Render a given template with template_vars as the context.

This is called automatically during dispatch() if auto_render is True and an action returns None.

For example:

def list(self):
    return render_template('planets/earth.html')

JSON

Handler provides a built-in method for JSON encoding python objects:

Handler.json(data, *args, **kwargs)[source]

Returns a json encoded string for the given object. Uses ferris.core.json_util so it is capable of handling Datastore types.

This can be used to respond to requests with JSON data easily:

def numbers(self):
    return self.json(range(0,100))

Note

You will have to set the content-type header to application/json manually. If many actions are responding with JSON, you can set this header in the startup() callback.

Keys

When passing ndb.Keys in parameters or URLs, use the following methods to encode & decode them:

Handler.url_key_for(item)

Returns a properly formatted urlsafe version of an ndb.Key.

Handler.key_from_string(str, kind=None)[source]

Returns an ndb.Key object from a properly formatted urlsafe version.

For example:

@route
def one(self):
    item = Widget.find_by_name('screwdriver')
    return self.redirect(self.uri(action='two', id=self.url_key_for(item)))

@route
def two(self, id):
    item = self.key_from_string(id).get()
    return item.name

Callbacks and Events

Handlers have various callbacks and events that are called during the lifecycle of a request.

Events

For a usual request, the order is:

  1. template_vars
  2. before_build_components, after_build_components
  3. before_startup, startup(), after_startup
  4. is_authorized
  5. before_dispatch, after_dispatch
  6. template_names (only if _get_template_name() is called)
  7. before_render, after_render (only if a template is rendered)
  8. dispatch_complete

You can tap into these events using Handler.events which is a NamedEvents instance:

def startup(self):
    self.events.before_dispatch += self.on_after_dispatch

The usual spot to register event listeners is in the startup() callback (inside a handler) or during construction inside a component.

These events are broadcasted to the global event bus with the prefix handler_.

Callbacks

To ease the use of these events while inside a handler, you can override the following callback methods:

Handler.startup()[source]

Called when a new request is received before authorization and dispatching.

Handler.before_dispatch()[source]

Called during dispatch before control is handed over to the action

Handler.after_dispatch(response)[source]

Called during dispatch after control is handed back from the action

Handler.before_render()[source]

Called during render_template before invoking the template engine

Handler.after_render(result)[source]

Called during render_template after the template has been rendered by the template engine

Table Of Contents

Previous topic

Models

Next topic

Routing

This Page