如何看到生成django模板变量的异常?

时间:2010-11-29 16:49:08

标签: python django django-templates

在Django模板中,可以调用这样的对象方法:

{{ my_object.my_method }}

问题是当你在'def my_method(self)'中遇到异常/错误时,它会在渲染模板时被隐藏(相反,会有一个空字符串输出,所以不会出现错误。)

由于我想调试'def my_method(self)'中的错误,我想打开类似全局django标志的东西来接收这样的异常。

在settings.py中

,我已经

DEBUG = True 
TEMPLATE_DEBUG = True

我可以接收多种模板异常,但是当我触发对象方法时没有。

我该怎么办?

6 个答案:

答案 0 :(得分:14)

这是我刚刚实现的一个很好的技巧。把它放在你的调试设置中:

class InvalidString(str):
    def __mod__(self, other):
        from django.template.base import TemplateSyntaxError
        raise TemplateSyntaxError(
            "Undefined variable or unknown value for: %s" % other)

TEMPLATE_STRING_IF_INVALID = InvalidString("%s")

当分析看到未知或无效值时,这将导致引发TemplateSyntaxError。我已经对此进行了一些测试(使用未定义的变量名称)并且效果很好。我没有测试函数返回值等。事情可能会变得复杂。

答案 1 :(得分:3)

最后我找到了一个解决方案:我开发了一个模板调试标签:

from django import template
import traceback

class DebugVariable(template.Variable):
    def _resolve_lookup(self, context):
        current = context
        for bit in self.lookups:
            try: # dictionary lookup
                current = current[bit]
            except (TypeError, AttributeError, KeyError):
                try: # attribute lookup
                    current = getattr(current, bit)
                    if callable(current):
                        if getattr(current, 'alters_data', False):
                            current = settings.TEMPLATE_STRING_IF_INVALID
                        else:
                            try: # method call (assuming no args required)
                                current = current()                            
                            except:
                                raise Exception("Template Object Method Error : %s" % traceback.format_exc())
                except (TypeError, AttributeError):
                    try: # list-index lookup
                        current = current[int(bit)]
                    except (IndexError, # list index out of range
                            ValueError, # invalid literal for int()
                            KeyError,   # current is a dict without `int(bit)` key
                            TypeError,  # unsubscriptable object
                            ):
                        raise template.VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
                except Exception, e:
                    if getattr(e, 'silent_variable_failure', False):
                        current = settings.TEMPLATE_STRING_IF_INVALID
                    else:
                        raise
            except Exception, e:
                if getattr(e, 'silent_variable_failure', False):
                    current = settings.TEMPLATE_STRING_IF_INVALID
                else:
                    raise

        return current

class DebugVarNode(template.Node):
    def __init__(self, var):
        self.var = DebugVariable(var)

    def render(self, context):
        return self.var.resolve(context)

@register.tag('debug_var')
def do_debug_var(parser, token):
    """
    raise every variable rendering exception, TypeError included (usually hidden by django)

    Syntax::
        {% debug_var obj.my_method %} instead of {{ obj.my_method }}        
    """
    bits = token.contents.split()
    if len(bits) != 2:
        raise template.TemplateSyntaxError("'%s' tag takes one argument" % bits[0])
    return DebugVarNode(bits[1])

所以现在在我的模板中我只需要替换

{{ my_object.my_method }} by {% debug_var my_object.my_method %}

答案 2 :(得分:2)

我会使用Unit tests来解决问题。我知道这是一个间接的答案,但我觉得这是解决和防止问题返回的理想方式。

答案 3 :(得分:2)

int totRev = air.getRevMiles() * 100 / totRevMiles(); int totPop = air.getPassMiles() * 100 / totPassMiles(); 对我不起作用。快速解决方法是打开TEMPLATE_STRING_IF_INVALID,找到env/lib64/python2.7/site-packages/django/template/base.py并在其中放置except Exception(假设您正在使用print e并且可以看到打印输出。)

然而,几行是manage.py runserver。尽管设置了current = context.template.engine.string_if_invalid,但我注意到string_if_invalid是空的。这引导我阅读这部分文档:

https://docs.djangoproject.com/en/1.8/ref/templates/upgrading/#the-templates-settings

  

当Django获得对多个模板引擎的支持时,Django的模板系统在Django 1.8中进行了大修。

     

...

     

如果您的设置模块定义了TEMPLATE_STRING_IF_INVALIDALLOWED_INCLUDE_ROOTS,请在“TEMPLATE_STRING_IF_INVALID”的“allowed_include_roots”和“string_if_invalid”键下添加其值字典。

所以除了@slacy's TemplateSyntaxError技巧,

OPTIONS

您还需要按如下方式定义class InvalidString(str): def __mod__(self, other): from django.template.base import TemplateSyntaxError raise TemplateSyntaxError( "Undefined variable or unknown value for: %s" % other) TEMPLATE_STRING_IF_INVALID = InvalidString("%s")

string_if_invalid

直接找到了一堆我甚至都不知道的问题。它确实应该默认启用。要解决期望无声地失败的标签和过滤器,我会在它们周围抛出条件:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'string_if_invalid': TEMPLATE_STRING_IF_INVALID,
            ...

虽然我怀疑这只有效,因为{% if obj.might_not_exist %} {{ obj.might_not_exist }} {% endif %} 无声地失败了。另一种方法可能是创建{% if %}过滤器:hasattr

答案 4 :(得分:1)

  

我该怎么办?

在视图函数中评估异常生成方法。

def someView( request ):
    .... all the normal work ...

    my_object.my_method() # Just here for debugging.

    return render_to_response( ... all the normal stuff... )

您可以在完成调试后删除该行代码。

答案 5 :(得分:0)

与S. Lott的答案类似,激活管理shell(python manage.py shell)并创建my_object的相应实例,调用my_method。或者将异常处理放在my_method中并记录异常。