Контекстный процессор с использованием Werkzeug и Jinja2
-
22-08-2019 - |
Вопрос
Мое приложение работает на App Engine и реализовано с использованием Веркцойг и Джинджа2.Я хотел бы иметь что-то функционально эквивалентное собственному контекстному процессору Django:вызываемый объект, который принимает запрос и добавляет что-то в контекст шаблона.У меня уже есть «обработчики контекста», которые добавляют что-то в контекст шаблона, но как мне это получить? запрос часть работает?Я реализовал процессоры контекста как вызываемые объекты, которые просто возвращают словарь, который позже используется для обновления контекста.
Например, я хотел бы добавить что-то, что содержится в request.environ
.
Решение
Один из способов добиться этого – поздняя привязка Глобальные переменные шаблона используя локальный прокси потока в Веркцойге.
Простой пример помещения запроса в глобальные переменные шаблона:
from werkzeug import Local, LocalManager
local = Local()
local_manager = LocalManager([local])
from jinja2 import Environment, FileSystemLoader
# Create a global dict using the local's proxy to the request attribute
global_dict = {'request': local('request')}
jinja2_env = Environment(loader=FileSystemLoader('/'))
jinja2_env.globals.update(global_dict)
def application(environ, start_response):
"""A WSGI Application"""
# later, bind the actual attribute to the local object
local.request = request = Request(environ)
# continue to view handling code
# ...
application = local_manager.make_middleware(application)
Теперь в любом из ваших шаблонов текущий запрос будет привязан к переменной «request».Конечно, это может быть что угодно в окружающей среде.Хитрость заключается в том, чтобы использовать локальный прокси, а затем установить значение перед визуализацией любого шаблона.
Вероятно, мне следует также добавить, что такая структура, как Гласхаммер (Werkzeug+Jinja2) упрощает этот процесс с помощью событий.Многие функции могут подключаться к событиям во время процесса вызова WSGI (например, при создании запроса) и в этот момент помещать данные в пространство имен шаблона.
Другие советы
Ну, используя что написал Али Я пришел к решению, специфичному для App Engine (из-за его кеша импорта).К сожалению, код Али не работает с App Engine, поскольку код, устанавливающий глобальные переменные Jinja, импортируется только один раз (что делает глобальные переменные фактически статичными).
мне пришлось написать свой собственный render()
функцию и обновите там контекст.Для полноты картины ниже приведен код, к которому я пришел:
def render(template, **kwargs):
response_code = kwargs.pop('response_code', 200)
mimetype = kwargs.pop('mimetype', 'text/html')
for item in getattr(settings, 'CONTEXT_PROCESSORS', []):
try:
processor = import_string(item)
kwargs.update(processor(local.request))
except (ImportError, AttributeError), e:
logging.error(e)
return Response(jinja_env.get_template(template).render(**kwargs),
status=response_code, mimetype=mimetype)
Это особенность App Engine.В других средах код Али работает так, как ожидалось (именно поэтому я меняю свой вопрос).