在 Django 模板中显示未定义的变量错误?

问题描述 投票:0回答:9

当 Django 在渲染模板时遇到未定义的变量错误时,我怎样才能告诉我?

我已经尝试了明显的

DEBUG = True
TEMPLATE_DEBUG = True
,但它们没有帮助。

django django-templates
9个回答
25
投票

将其放入调试设置中:

class InvalidString(str):
    def __mod__(self, other):
        from django.template.base import TemplateSyntaxError
        raise TemplateSyntaxError(
            "Undefined variable or unknown value for: \"%s\"" % other)
  • 来自最近的 Django 版本:
TEMPLATES = [
    {
        (...)
        'OPTIONS': {
            (...)
            'string_if_invalid': InvalidString("%s")
        },
    },
]
  • 来自姜戈< 1.8:
TEMPLATE_STRING_IF_INVALID = InvalidString("%s")

当模板引擎看到或发现未定义的值时,这应该会引发错误。


11
投票

根据 django 文档, 默认情况下,未定义的变量被视为“”(空字符串)。而在 if for regroup 中,它是 None。 如果您要识别未定义的变量,请更改设置中的 TEMPLATE_STRING_IF_INVALID。 '%s' 使无效变量被渲染为其变量名,这样您就可以轻松识别。 如何处理无效变量


6
投票

查找上下文中不存在的模板变量对我来说很重要,因为多次出现错误,因为视图已更改但模板没有更改。

我使用了这种技术,在

manage.py
中实现,以达到在使用上下文中找不到的模板变量时破坏测试的效果。请注意,此技术适用于
for
循环和
if
语句,而不仅仅是
{{ variables }}

import sys

# sometimes it's OK if a variable is undefined:
allowed_undefined_variables = [
    'variable_1',
    'variable_2',
]

if 'test' in sys.argv:
    import django.template.base as template_base

    old_resolve = template_base.Variable.resolve

    def new_resolve(self, context):
        try:
            value = old_resolve(self, context)
        except template_base.VariableDoesNotExist as e:
            # if it's not a variable that's allowed to not exist then raise a
            # base Exception so Nodes can't catch it (which will make the test
            # fail)
            if self.var not in allowed_undefined_variables:
                raise Exception(e)

            # re-raise the original and let the individual Nodes deal with it
            # however they'd like
            raise e

        return value

    template_base.Variable.resolve = new_resolve

6
投票

如何记录模板中未定义变量的警告

Django 似乎依赖于未定义的变量作为一个简单的空字符串。因此,我们不要更改此行为或使其抛出异常,而是保持不变,但让它记录警告!

在您的

settings.py
文件中:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # ...
        'OPTIONS': {
            # ...
            'string_if_invalid': InvalidStringShowWarning("%s"),
        },
    }
]

(在较新的 Django 版本中,

string_if_invalid
取代了
TEMPLATE_STRING_IF_INVALID
。)

更进一步,您需要定义

InvalidStringShowWarning
类,使其在记录警告时表现良好:

class InvalidStringShowWarning(str):
    def __mod__(self, other):
        import logging
        logger = logging.getLogger(__name__)
        logger.warning("In template, undefined variable or unknown value for: '%s'" % (other,))
        return ""

    def __bool__(self): # if using Python 2, use __nonzero__ instead
        # make the template tag `default` use its fallback value
        return False

您应该能够在

python manage.py runserver
的输出中看到警告。


3
投票

我认为这是 Django 的一个重大疏忽,也是我不喜欢使用他们的默认模板引擎的主要原因。可悲的事实是,至少现在(Django 1.9),你无法可靠地实现这种效果

  • 可以让Django在遇到

    {{ undefined_variable }}
    时引发异常 - 通过使用slacy的答案中描述的“黑客”。

  • 不能让Django在

    {% if undefined_variable %}
    {% for x in undefined_variable %}
    等上引发相同的异常。“黑客”在这种情况下不起作用。

  • 即使在可以的情况下,Django 作者也强烈建议不要在生产环境中使用此技术。除非您确定不在应用程序中使用 Django 的内置模板,否则您应该在 DEBUG 模式下使用“the hack”

    only

但是,如果你现在坚持使用 Django 的模板,我建议使用 slacy 的答案,只需确保你处于

DEBUG
模式即可。


2
投票

阅读模板中如何处理无效变量。基本上,只需将 TEMPLATE_STRING_IF_INVALID 设置为 settings.py 中的某些内容即可。

TEMPLATE_STRING_IF_INVALID = "He's dead Jim! [%s]"

1
投票

我接下来使用:

import logging

from django.utils.html import format_html
from django.utils.safestring import mark_safe


class InvalidTemplateVariable(str):
    """
    Class for override output that the Django template system
    determinated as invalid (e.g. misspelled) variables.
    """

    # styles for display message in HTML`s pages
    styles = mark_safe('style="color: red; font-weight: bold;"')

    def __mod__(self, variable):
        """Overide a standart output here."""

        # access to current settings
        from django.conf import settings

        # display the message on page in make log it only on stage development
        if settings.DEBUG is True:

            # format message with captured variable
            msg = 'Attention! A variable "{}" does not exists.'.format(variable)

            # get logger and make
            logger = self.get_logger()
            logger.warning(msg)

            # mark text as non-escaped in HTML
            return format_html('<i {}>{}</i>', self.styles, msg)

        # on production it will be not displayed
        return ''

    def get_logger(self):
        """Create own logger with advanced error`s details."""

        logger = logging.getLogger(self.__class__.__name__)

        logger.setLevel(logging.DEBUG)

        handler = logging.StreamHandler()
        handler.setLevel(logging.DEBUG)

        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

        handler.setFormatter(formatter)

        logger.addHandler(handler)

        return logger

在设置文件中使用(默认为settings.py):

TEMPLATES = [
    {
        ......
        'OPTIONS': {
            .....................
            'string_if_invalid': InvalidTemplateVariable('%s'),
            .....................
        },

    },
]

或直接

TEMPLATES[0]['OPTIONS']['string_if_invalid'] = InvalidTemplateVariable('%s')

DEBUG = True 时的结果:

在页面上

在控制台中

> System check identified 1 issue (0 silenced). October 03, 2016 -
> 12:21:40 Django version 1.10.1, using settings 'settings.development'
> Starting development server at http://127.0.0.1:8000/ Quit the server
> with CONTROL-C. 2016-10-03 12:21:44,472 - InvalidTemplateVariable -
> WARNING - Attention! A variable "form.media" does not exists.

0
投票

您可以使用 pytest-django 设置 FAIL_INVALID_TEMPLATE_VARS

如果 pytest 执行代码,则会检查无效的变量。

[pytest]
DJANGO_SETTINGS_MODULE = mysite.settings
FAIL_INVALID_TEMPLATE_VARS = True

-4
投票

如果模板中有未定义的变量,django不会告诉你。

您可以在视图中打印这个变量。

© www.soinside.com 2019 - 2024. All rights reserved.