Django - доступ к RequestContext из настраиваемого фильтра

У меня есть фильтр currency, который принимает значение в долларах США и конвертирует его в валюту (доллары США или фунты стерлингов). Валюта, в которую нужно конвертировать, хранится в сеансе, но фильтры не принимают RequestContext, поэтому я не могу получить ее прямо оттуда.

Есть ли лучший способ, чем передача соответствующего элемента сеанса в шаблон и из шаблона в фильтр в качестве аргумента? Хотя этот подход работает, он кажется довольно ужасным, и я, вероятно, в конечном итоге передам валюту (почти) каждому шаблону.

Мой фильтр сейчас выглядит примерно так:

def currency(value, currency):
    if currency == 'usd':
       val = '$%.2f' % value
       return mark_safe(val)

    d = Decimal(value)
    val = '£%.2f' % (d*Decimal('0.63'))

    return mark_safe(val)

person Dominic Rodger    schedule 29.09.2009    source источник


Ответы (4)


Если вы создаете тег шаблона вместо фильтра, вам предоставляется контекст для работы (который содержит запрос). http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags.

person Adam    schedule 29.09.2009
comment
@Adam - возможно, я слишком толстый, но я не вижу в этих документах, как получить доступ к переменным сеанса из пользовательских тегов шаблонов. Не могли бы вы привести мне пример или указать, что мне не хватает? - person Dominic Rodger; 30.09.2009
comment
Ах, поиски, похоже, передаются в качестве первого аргумента тега (только что нашел пример, который добавляет класс к ссылкам, соответствующим регулярному выражению, которое выглядит (а) полезным и (б) адаптируемым - gnuvince.wordpress.com/2007/09 / 14 /). - person Dominic Rodger; 30.09.2009
comment
Правильно, контекст - это стандартный параметр метода рендеринга в узле тега шаблона. Если вам нужен еще один конкретный пример, я уверен, что смогу собрать его. - person Adam; 30.09.2009
comment
Что ж, глядя на пример в опубликованном URL-адресе, это не совсем то же самое, поскольку автор явно передает запрос. Если вы пишете тег шаблона как смесь методов компиляции и рендеринга, контекст передается без явного выполнения каких-либо действий из шаблона. - person Adam; 30.09.2009

Я должен согласиться с Адамом в том, что лучше всего перенести код на настраиваемый тег.

Однако клиенту необходимо было записывать использование определенных фильтров только тогда, когда страница была опубликована и имел ОГРОМНЫЙ перечень шаблонов, в которых использовался существующий синтаксис фильтра. Переписать все шаблоны было бы дорогостоящим мероприятием. Итак, я придумал эту простую функцию, которая извлекает контекст из стека вызовов:

https://gist.github.com/drhoden/e05292e52fd5fc92cc3b

def get_context(max_depth=4):
    import inspect
    stack = inspect.stack()[2:max_depth]
    context = {}
    for frame_info in stack:
        frame = frame_info[0]
        arg_info = inspect.getargvalues(frame)
        if 'context' in arg_info.locals:
            context = arg_info.locals['context']
            break
    return context

Обязательно прочтите мои предупреждения, но это ДЕЙСТВИТЕЛЬНО дает стандартным фильтрам доступ к контексту (если он доступен) БЕЗ необходимости превращать ваш фильтр в тег.

person Daniel Rhoden    schedule 22.01.2015
comment
Это круто, не уверен, круто в хорошем или плохом, но круто;) - person jb.; 08.03.2017
comment
Я одновременно чрезвычайно впечатлен и чрезвычайно напуган. Отлично. : D - person thms; 16.04.2021

Это можно сделать с помощью фильтра. Сначала убедитесь, что в вас "django.core.context_processors.request" TEMPLATE_CONTEXT_PROCESSORS. Если вы этого не сделаете, вы можете добавить это в свой файл settings.py:

TEMPLATE_CONTEXT_PROCESSORS += (
    "django.core.context_processors.request"
)

Тогда в вашем шаблоне ваш фильтр будет выглядеть так (при условии, что ваша переменная сеанса называется «currency_type»):

{{value|currency:request.session.currency_type}}

Или что-то подобное вы считаете довольно ужасным?

person Zach    schedule 02.10.2009
comment
Он; Посмотрите, что он делает, этот фильтр точно описывает то, что вы говорите. - person fijter; 03.10.2009
comment
Я подумал, что он может жаловаться на процесс явной передачи переменной через представление. Это сделает его доступным автоматически. Я также могу опубликовать пример использования тега шаблона с take_context = True в декораторе - person Zach; 03.10.2009

Как-то менее хакерское решение предложения Дэниела Родена - использовать threading.local(). Определите класс промежуточного программного обеспечения, который хранит ваш request как глобальный объект внутри вашего локального потока, и добавьте этот класс в ваш MIDDLEWARE_CLASSES.

Теперь фильтр шаблона может легко получить доступ к этому объекту запроса.

person jrief    schedule 18.02.2015