Patrice's Blog

A few things I learned about Flask, WTForms, Jinja2 and NDB

Flask comes with very good documentation, tutorials and examples, that is one of its great strength, and makes for an efficient learning curve.

And yet, there are a few things that somehow I missed in the docs, and that took me a few weeks to figure out.    Here are a few, with no particular order.

flask.g is not global

Flask provides a ‘g’ object, but although this may sound like ‘global’, it is not.   The g object only has the lifespan of a single request, so using g is not very much different from using a request object.   If a request is handled within a single function, then g is not of much use.   One specific use of g is when you have a @before_request callback defined, that will prepare the environment for the actual request handler.   For example, it might get a database query, or retrieve some data from memcache, or data storage, and make this data available to request handlers.   In such a case, the @before_request function would use g to make the data available.

Note that flask.g is available to Jinja2 templates as well.   Suppose you have a dynamic list of menu items that are displayed in the menu of the application, on every page.  When a request handler completes and calls render_template, it would have to retrieve the list of menu items and pass the list to render_template.

Suppose the items are in a very simple Ndb model:

class MenuItem(ndb.Model):
    item = ndb.StringProperty()

    @staticmethod
    def get_items():
        return MenuItem.query().fetch()

Then every single request handler in our app would need to call render_template adding “menu_items = MenuItem.get_items()”, which is ridiculous.

The flaskonic way to do this, it seems, is to add the menu_items list into g within a @before_request, then insert this in the menu within the base.html template, the one that all templates extend by {% extends “base.html” %}, and which defines the global navigation.

So it would be like this:

@main.before_request
def load_menu_items():
    menu_items = g.get('menu_items', None)
    if not menu_items:
        g.menu_items = MenuItem.get_items()

And this could use memcache as well of course.

The Jinja2 template simply uses g.menu_items, which is always available.

There is no global persistent storage

… that is to say other than your database, memcache, or the like.   I spent some time looking for it.   Because memcache is fast, but memory is even faster.  So you would think that for some small stuff that needs to be available in almost every single request processing, say like the menu items above, you would be more efficient having them in some sort of global memory object, instead of retrieving them from memcache at the start of every request handling.   But it seems there is none, so memcache is the way to go.

To be continued

I will add to this post as I find time.

Comments are closed.