When creating a page that involves a hefty amount of logic and/or external services to be queried in addition to a complex or large HTML page, one generally ends up caching in two places.
The biggest problem with this pattern is that in the best-case scenario, where the HTML output is cached and the section of the controller for that portion is cached, there is still retrieval of the serialized objects in the controller for the template. This occurs even though the template output is still cached.
To remedy this, one can mark the section in the controller that should be run when the cached template output is no longer available, or when it should be considered invalid.
First, the necessary Python code, consider putting this in lib/component.py:
import beaker.cache from beaker.util import func_namespace from beaker.session import SHA1 def component_cached(region, *args): """Associate a callable with a cached page component. the page component should call the "render" def in conditional_cache.mako. The cache itself is local to the template in the render() call. """ key = " ".join(str(x) for x in args) region = beaker.cache.cache_regions[region] def decorate(func): def cached(*args): cache_key = key + " " + " ".join(str(x) for x in args) def go(): return func(*args) cache_rec = { 'data_key':SHA1(func_namespace(func) + cache_key).hexdigest(), 'region':region, 'callable':go, } return cache_rec return cached return decorate def invalidate_component_cached(source): """Takes the source information returned when calling a component_cached function, and marks it to be invalidated""" source['invalidate'] = True return source
Then create a Mako template called /component.mako:
<%def name="render(source)"><% cache_rec = source cachens = caller.context.get('self') def go(): result = cache_rec['callable']() return capture(caller.body, **result) if cache_rec.get('invalidate', False): cache = cachens.cache.invalidate(cache_rec['data_key']) region = cache_rec['region'].copy() if 'expire' in region: region['expiretime'] = region.pop('expire') context.write( cachens.get_cached(cache_rec['data_key'], createfunc=go, **region) ) %></%def>
Inside a controller action, import the code and use it to indicate a section should be cached:
from datetime import datetime from pylons import tmpl_context as c from mako_sample.lib.base import BaseController, render from mako_sample.lib.component import component_cached class HelloController(BaseController): def index(self): @component_cached('short_term') def some_func(name): now = datetime.now() return dict(result='%s, the time is %s' % (name, now)) c.func_src = some_func('fred') return render('/test.mako')
In this example, some_func will be cached. Repeat calls to the cached function where the output is changing should be assigned to another 'c' variable for use in the template. This variable is used to pass the reference to the function in so that the template can trigger it should its output be invalidated.
'short_term' here refers to a cache region. See the Beaker docs for more information on configuring cache regions in your Pylons application.
Now inside the template:
Hello, the cached data: <%cache:render args="result" source="${c.func_src}"> The result is ${result} </%cache:render> <%namespace name="cache" file="/component.mako"/>
Some things to notice...
The cached function should return a dict, the keys of it will then be passed into the namespace render function in the template (this is why we're indicating in the template that it expects the args of 'result' back).
Second, while the triggering of the function happens from the template we still get the clean code separation of concerns by not having a ton of controller type logic inside the template itself.
To invalidate the cache, merely determine if it should be invalid in the controller, and use the invalidate function supplied:
from mako_sample.lib.component import component_cached, invalidate_component_cached class HelloController(BaseController): def index(self): @component_cached('short_term') def some_func(name): now = datetime.now() return dict(result='%s, the time is %s' % (name, now)) c.func_src = some_func('fred') if something: invalidate_component_cached(c.func_src) return render('/test.mako')
Powered by Pylons - Contact Administrators
Comments (10)
Wow, there is really much useful data here!
Caching can cause issues and you have a workaround that appears to work. sim only contracts
More often than not I do not post on websites, but I would just like to say that this article has compelled me to do so! Thanks for your perceptive article.
Regards,
Who Can Write My Essay For Me
It’s a high-quality summary that you have written. There are a number of points however which I believe would do better if you went into a little bit further detail than you have done. simply my opinion,plus I’m not trying to be critical at all. If you do follow this up then I would be interested. Thanks.
Escorts Las Vegas
I think that thanks for the valuabe information and insights you have so provided here. payday advance online
I know the things you signify I just want much more persons might understand this also. Who knows perhaps some day they’ll. Keep posting flex seal reviews such thoughts during the potential future too.
A supplier usually gives a pattern product in an occasion. In any other case, people can get it inside the magazine. Some product agencies usually have collaboration with media as part of the advertising. cigarette sales
This subject has interested me for quite some time. I have just started vistaril for anxiety researching it on the Internet and found your post to be informative. Thanks
I wanted to say that it’s nice art degree to know that someone else also mentioned Law School this as I had trouble finding the same Natural sciences degree info elsewhere business degree. This was the first place that told me the answer Computer Science degree.
You must login before you can comment.