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

20 投票
4 回答
15789 浏览
提问于 2025-04-15 14:41

我有一个叫做 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)

4 个回答

5

这可以通过使用一个过滤器来实现。首先,确保你的 TEMPLATE_CONTEXT_PROCESSORS 中有 "django.core.context_processors.request" 这个内容。如果没有的话,你可以把它添加到你的 settings.py 文件里:

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

然后在你的模板中,你的过滤器看起来会像这样(假设你的会话变量叫做 'currency_type'):

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

或者你考虑的这种方式是不是觉得非常糟糕呢?

8

我同意亚当的看法,把代码迁移到自定义标签是最好的方法。

不过,有个客户需要在页面发布时记录某些过滤器的使用情况,而且他们有很多模板都在用现有的过滤器语法。如果要重写所有模板,那可真是个大工程,成本也会很高。所以,我想出了一个简单的函数,可以从调用堆栈中提取上下文:

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

一定要看看我的警告,不过这个方法确实可以让标准过滤器在有上下文的情况下访问这些信息,而不需要把你的过滤器变成标签。

13

如果你创建一个模板标签而不是过滤器,你会得到一个可以使用的上下文(里面包含了请求的信息)。 http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags

撰写回答