Tornado Web Framework - Flash Messages

Implement flash messages in Tornado web framework.

Problem

Suppose you have a URL for editing an object under /OBJECT-ID/edit. Normally when user fills in the information on that page and presses the submit button, the request is sent to /OBJECT-ID/update which persists the data. But if the the data provided by user is not valid, you need to redirect user the to /OBJECT-ID/edit along with the provided data and validation errors, so s/he can correct it.
The clean and preferred way to do this is by using flash cookies.

Code

All the source code provided in this post, is licensed under Apache License 2.0.
import re
import pickle
from tornado.escape import to_unicode
from tornado import web, escape


class Flash(object):
    """
    A flash message along with optional (form) data.
    """

    def __init__(self, message, data=None):
        """
        'message': A string.
        'data': Can be anything.
        """
        self.message = message
        self.data = data


class MyHandler(tornado.web.RequestHandler):
    """
    Extends Tornado's RequestHandler by adding flash functionality.
    """

    def _cookie_name(self, key):
        return key + '_flash_cookie' # change this to store/retrieve flash
                                    # cookies under a different name

    def _get_flash_cookie(self, key):
        return self.get_cookie(self._cookie_name(key))

    def has_flash(self, key):
        """
        Returns true if a flash cookie exists with a given key (string);
        false otherwise.
        """
        return self._get_flash_cookie(key) is not None

    def get_flash(self, key):
        """
        Returns the flash cookie under a given key after converting the
        cookie data into a Flash object.
        """
        if not self.has_flash(key):
            return None
        flash = tornado.escape.url_unescape(self._get_flash_cookie(key))
        try:
            flash_data = pickle.loads(flash)
            self.clear_cookie(self._cookie_name(key))
            return flash_data
        except:
            return None

    def set_flash(self, flash, key='error'):
        """
        Stores a Flash object as a flash cookie under a given key.
        """
        flash = pickle.dumps(flash)
        self.set_cookie(self._cookie_name(key), tornado.escape.url_escape(flash))

How To Use

Sample handlers that use flash cookies.
class Edit(MyHandler):
    def get(self, record_id):
        if self.has_flash('error'):
            flash = self.get_flash('error')
            self.render('edit_template.html', form=flash.data, flash_msg=flash.message)
        else:
            self.render('edit_template.html', form=get_form_data())


class Update(MyHandler):
    def post(self, short_url):
        form = get_submitted_data()
        if not form.validate():
            flash = Flash('Form has errors', form)
            self.set_flash(flash, 'error')
            self.redirect('edit_template.html')
        else:
            self.do_update(short_url, form)
            self.redirect('show_template.html')

Notes

Remember to use get_secure_cookie and set_secure_cookie in MyHandler for production mode.

Comments

Popular posts from this blog

Variables in GNU Make: Simple and Recursive

Checkmate on Your Terms: A Personal Journey with Correspondence Chess

Firefox profiles: Quickly replicate your settings to any machine