2009-02-11 7 views
4

Мое приложение работает на App Engine и реализовано с использованием Werkzeug и Jinja2. Я хотел бы иметь что-то функционально эквивалентное собственному процессору контекста Django: вызываемый, который принимает запрос и добавляет что-то в контекст шаблона. У меня уже есть «процессоры контекста», которые добавляют что-то в контекст шаблона, но как мне получить этот запрос ? Я реализовал контекстные процессоры как вызывающие, которые просто возвращают словарь, который позже используется для обновления контекста.Контекстный процессор с использованием Werkzeug и Jinja2

Например, я хотел бы добавить что-то, что содержится в request.environ.

+0

+1. Я бы хотел, чтобы все вопросы были так же хорошо сформированы, как и этот. –

ответ

4

Один из способов достижения этого - через поздний период template globals с использованием thread-local proxy в Werkzeug.

Простой пример, который помещает запрос в глобалов шаблона:

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) 

Теперь в любом из ваших шаблонов, текущий запрос будет казаться привязан к переменной «запрос». Конечно, это может быть что-то еще в среде. Фокус в том, чтобы использовать локальный прокси-сервер, а затем установить значение перед визуализацией любого шаблона.

Я также должен добавить, что фреймворк, такой как Glashammer (Werkzeug + Jinja2), упрощает этот процесс для вас, используя события. Многие функции могут подключаться к событиям во время вызова WSGI (например, когда создается запрос), и они могут помещать материал в пространство имен шаблонов в этой точке.

+0

Конструктор Environment не принимает аргумент «globals» - это атрибут экземпляра среды (вы должны изменить его сразу после создания env). Помимо этого, это совершенно то, что я искал. Спасибо. – zgoda

+0

Ах, спасибо, я обновлю пример. Я сделал это по памяти. –

+0

К сожалению, это невозможно сделать с AppEngine из-за кэша импорта (импортированные модули кэшируются между запросами) - globals dict (и объект запроса) будут кэшироваться до перезагрузки модуля. – zgoda

3

Ну, используя what Ali wrote Я пришел к решению, специфичному для 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) 

Это особый двигатель для приложений. В других средах код Али работает так, как ожидалось (и именно поэтому я возвращаю свой вопрос).