'How do I access a context_processor from within a method route in Flask?
I'd like to setup variables available to both my views and my methods without polluting the request object in a before_request decorator.
Context processors seems like a nice way to do this however, I can't figure out how to actually access them from within my methods.
The best solution I have come up with is to memoize the context function so that it doesn't get called twice, once by me in my method and then again when Flask injects it into the template.
However, this will cache the method for all future requests and I only want it cached per request.
Here is my working example
from functools import cache
@app.context_processor
@cache
def setup_context():
return {
'planet': db.query('select planet from planets order by random()').first()
}
@app.route("/")
def index():
ctx = setup_context()
if ctx['planet'] == 'pluto':
return redirect('/pluto-is-not-a-planet')
return render_template('planet_greeting.html')
Any ideas on how to accomplish this without using functools.cache?
Solution 1:[1]
There may be a more elegant way to do this but here is what I have come up with so far.
The basic idea is to use the extensions pattern and create an object "Current" that the app gets passed to.
I can then use properties on this object to access the _app_ctx_stack as well as populate templates with context variables using the context_processor hook.
This approach will allow me to have templates that don't use "g" and a nice object to work with in my routes.
from flask import (
Flask, current_app, _app_ctx_stack,
render_template as template
)
from random import shuffle
planets = ['earth', 'pluto', 'mars']
class Current(object):
def __init__(self, app=None):
self.app = app
self.app.context_processor(self.context_processor)
def context_processor(self):
return _app_ctx_stack.top.__dict__
@property
def planet(self):
ctx = _app_ctx_stack.top
if not hasattr(ctx, 'planet'):
shuffle(planets)
ctx.planet = {
'name': planets[0]
}
return ctx.planet
app = Flask(__name__)
current = Current(app)
@app.route("/")
def index():
if current.planet['name'] == 'pluto':
return "Pluto is not a planet!"
return template("planet.html")
if __name__ == '__main__':
app.run(debug=True)
And in my template
{%# in my template %}
The planet is {{ planet.name }}!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | seanbehan |
