Ответ 1
Если вы создаете тег шаблона вместо фильтра, вам предоставляется контекст для работы с (который содержит запрос). http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags
У меня есть фильтр currency
, который принимает значение в долларах США и конвертирует его в валюту (USD или GBP). Валюта для конвертирования в хранится в сеансе, но фильтры не принимают 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)
Если вы создаете тег шаблона вместо фильтра, вам предоставляется контекст для работы с (который содержит запрос). http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags
Это можно сделать с помощью фильтра. Сначала убедитесь, что у вас "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}}
Или что-то вроде этого, что вы считаете довольно ужасным?
Я бы согласился с Адамом, что наилучшим способом является перенос кода на пользовательский тег.
Тем не менее, клиенту необходимо было зарегистрировать использование определенных фильтров только в том случае, если страница была опубликована, и у нее был огромный каталог шаблонов, в которых использовался существующий синтаксис фильтра. Было бы дорогостоящим обязательством переписать все шаблоны. Итак, я придумал эту простую функцию, которая извлекает контекст из стека вызовов:
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
Обязательно прочтите мои предупреждения, но это дает стандартным фильтрам доступ к контексту (когда он доступен) БЕЗ необходимости превратить ваш фильтр в тег.
Как-то менее хакерское решение для предложения Даниэля Родена - использовать threading.local()
. Определите класс промежуточного программного обеспечения, в котором ваш request
будет храниться как глобальный объект внутри вашего локального потока и добавьте этот класс в ваш MIDDLEWARE_CLASSES
.
Теперь фильтр шаблонов может легко получить доступ к этому объекту запроса.