jinja2:如何像djangotemplate一样静默失败

6 投票
2 回答
2408 浏览
提问于 2025-04-16 18:39

我找不到答案,我相信这很简单,但我就是不知道怎么让它像Django那样在找不到变量时工作。

我尝试使用Undefined并自己创建一个undefined,但这给我带来了属性错误等问题。

def silently(*args, **kwargs):
    return u''

class UndefinedSilently(Undefined):
    __unicode__ = silently
    __str__ = silently
    __call__ = silently
    __getattr__ = silently

但是当我在这里尝试这个时,它失败了,出现了 TypeError: 'unicode' object is not callable

{%for dir_name, links in menu_links.items()%}

2 个回答

1

这是一个老问题,但它涉及到一个相关的主题。我重新提出来是为了帮助其他人,特别是关于Django 3.1/3.2/4.0的内容:

  1. 首先,找到你的 settings.py 文件。

  2. 在里面添加以下内容到 'OPTIONS' 部分:

    'undefined': jinja2.Undefined
    
  3. 这样做后,当你渲染页面时,未定义的变量就不会出现了,也就是说它们会“安静”地消失。完整的代码应该像这样:

    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [
            BASE_DIR / 'templates-jinja2'
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'environment': 'config.jinja2.environment',
            'context_processors': [],
            'undefined': jinja2.DebugUndefined
    
        },
    },
    
  4. 另外,你可以使用 DebugUndefined 来查看未定义的变量,或者使用 'StrictUndefined' 来在使用未定义变量时抛出异常。

10

你正在尝试深入访问一个未定义的数据。menu_links 是未定义的,所以 Jinja2 创建了一个新的 UndefinedSilently 类的实例。接着,它调用这个对象的 __getattr__ 方法来获取 items 属性。这个方法返回的是一个空的 Unicode 字符串。然后,Python 试图调用这个字符串(也就是 menu_links.items() 后面的 ()),结果就出现了错误,因为 Unicode 对象是不能被调用的。

也就是说:

menu_links.items() # becomes
UndefinedSilently().items() # becomes
UndefinedSilently().u''() # from UndefinedSilently.__getattr__

如果你想要能够深入访问超过一层,你可以创建一个类,让它在每次访问时都返回自己,除了在 __str____unicode__ 方法的调用。

def silently(*args, **kwargs):
    return u''

return_new = lambda *args, **kwargs: UndefinedSilently()

class UndefinedSilently(Undefined):
    __unicode__ = silently
    __str__ = silently
    __call__ = return_new
    __getattr__ = return_new

撰写回答