2010-11-29 54 views
15

里面Django模板,你可以这样调用对象方法:如何将异常生成到django模板变量中?

{{ my_object.my_method }} 

问题是,当你得到一个异常/错误“高清my_method(个体经营)”,呈现模板时是隐藏(有一个空字符串输出,所以没有错误出现)。

因为我想调试'def my_method(self)'中的错误,我想打开一个像全局django标志来接收这样的异常。

settings.py中,我已经有

DEBUG = True 
TEMPLATE_DEBUG = True 

我可以收到许多种模板例外,但没有当我trig的对象方法。

我该怎么办?

+1

我有完全相同的问题...我会认为这是一个在Django本身的错误... – 2012-01-13 13:07:54

回答

1

我该怎么办?

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

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

    my_object.my_method() # Just here for debugging. 

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

当您完成调试时,您可以删除该行代码。

+0

我已经使用这种方法,它很无聊:真的没有标志到Django来引发变量异常? – Eric 2010-11-30 08:37:32

+0

@Eric:“无聊”?对不起,工作让你无聊。也许你应该找到另一份工作。认真。单元测试会比这更好。在模板中查找异常意味着您无法使用适当的单元测试来调试模型和视图函数。你不需要在模板中找到异常,因为有更好的**方法,更简单,更可靠,更易于调试。对不起,这很无聊。 – 2010-11-30 10:52:54

0

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

2

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

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 %} 
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。我已经测试了一点(具有未定义的变量名称),并且效果很好。我还没有用函数返回值进行测试,等等。事情可能会变得复杂。

2

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。尽管设置了TEMPLATE_STRING_IF_INVALID,我注意到string_if_invalid是空的。这导致我的文档的这一部分:

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

Django的模板系统在Django 1.8被翻修时,它获得了多个模板引擎的支持。

...

如果您的设置模块定义ALLOWED_INCLUDE_ROOTSTEMPLATE_STRING_IF_INVALID,包括在“allowed_include_roots”和他们的价值观在“OPTIONS”字典“string_if_invalid”键。

所以除了@slacy's TemplateSyntaxError招,

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过滤器:{% if obj|hasattr:"might_not_exist" %}