Django - 从自定义过滤器中访问RequestContext

时间:2009-09-29 17:18:30

标签: python django django-templates

我有一个过滤器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)

4 个答案:

答案 0 :(得分:7)

如果您创建模板标记而不是过滤器,则会为您提供要使用的上下文(包含请求)。 http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags

答案 1 :(得分:4)

我不得不同意Adam,将代码迁移到自定义标记是最好的方法。

但是,客户端只需在发布页面时记录某些过滤器的使用情况,并且拥有大量使用现有过滤器语法的模板。重写所有模板将是一项代价高昂的工作。所以,我想出了这个从调用堆栈中提取上下文的简单函数:

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

请务必阅读我的警告,但这可以让标准过滤器访问上下文(当它可用时),而不必将过滤器变成标签。

答案 2 :(得分:3)

这可以使用过滤器完成。首先确保您"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}}

或者你认为这样的东西是相当可怕的吗?

答案 3 :(得分:0)

对于Daniel Rhoden的提议,使用threading.local()的方法不那么糟糕。定义一个中间件类,它将您的request作为全局对象存储在本地线程中,并将该类添加到MIDDLEWARE_CLASSES

现在,模板过滤器可以轻松访问该请求对象。