Skip to content

Instantly share code, notes, and snippets.

@gnunicorn
Created April 10, 2012 15:08
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gnunicorn/2352035 to your computer and use it in GitHub Desktop.
Save gnunicorn/2352035 to your computer and use it in GitHub Desktop.
memcache extension for Jinja2 on Google AppEngine
from google.appengine.api import memcache
from jinja2 import nodes
from jinja2.ext import Extension, next
"""
A great Jinja2 Extension for quicker caching of fully rendered content using
Memcache on AppEngine.
Activate this Extension by adding it to the list of Extension on your
Jinja2-Environment-Setup and you'll have a powerful jinja2-macro on
your hand. Then simply wrap the code you want to cached into
{% memcached "my_key" %}
... your template code here
{% endmemcached %}
and from the next time the page is rendered this features uses memcache to
cache and retrieve complete rendered parts of the webpage. You'll see an
immediate increase in response time from the second request.
You can do everything within the block - even include other templates.
When the Extension can't find the corresponding result in the memcache it
executes the code normally and saves the resulting string.
Note: If the given cache-key converts into a faulty value, the code is
executed always and the code never cached. This gives the user the ability
to force execution as the key can be an expression as usually:
{% memcached myModel.cache_key %}
... your template code here
{% endmemcached %}
Here for some models (those having a cache_key) caching is allowed, for
others (those where cache_key is False) it is prohibited and the code is
always executed.
*Note*: the key is never de-validated or deleted. Cache-validation
responsibility must be taken by the developer somewhere else. However you
can specify the max-timeout passed to the memcache-call by passing a number
as the second value when calling memcached:
{% memcached myModel.cache_key 3600 %}
... your template code here
{% endmemcached %}
================
2012 © by Benjamin Kampmann < ben . kampmann at gmail . com >
Latest version always available as a gist: https://gist.github.com/2352035
"""
class MemcachedExtension(Extension):
tags = set(["memcached"])
def parse(self, parser):
lineno = parser.stream.next().lineno
args = [parser.parse_expression(),
parser.stream.current.type != 'block_end' and
parser.parse_expression() or nodes.Const(None)]
body = parser.parse_statements(['name:endmemcached'], drop_needle=True)
return nodes.CallBlock(
self.call_method('_cache', args), [], [], body
).set_lineno(lineno)
def _cache(self, keyname, timeout, caller):
if not keyname:
return caller()
value = memcache.get(keyname)
if not value:
value = caller()
memcache.set(keyname, value, time=timeout or 0)
return value
memcached = MemcachedExtension
@alesasnouski
Copy link

How to connect it ? Have no ideas :(

@alesasnouski
Copy link

I try to connect it like this ...

def jinja2_factory(app):
j2 = jinja2.Jinja2(app)
j2.environment.filters.update({
# Set filters.
# ...
})
j2.environment.globals.update({
# Set global variables.
'uri_for': webapp2.uri_for,
# ...
})
j2.environment.extensions.update({'memcached': memcached(j2.environment)})
return j2

class BaseHandler(webapp2.RequestHandler):

@webapp2.cached_property
def jinja2(self):
    # Returns a Jinja2 renderer cached in the app registry.
    return jinja2.get_jinja2(app=self.app, factory=jinja2_factory)

def render_response(self, _template, **context):
    # Renders a template and writes the result to the response.
    rv = self.jinja2.render_template(_template, **context)
    self.response.write(rv)

@alesasnouski
Copy link

Use j2.environment.add_extension('blog.utils.memcached')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment