2010-11-29 2 views
15

Внутри шаблона Django, можно вызвать метод объекта, как это:Как увидеть исключение, сгенерированное в переменной шаблона django?

{{ my_object.my_method }} 

Проблема заключается в том, когда вы получаете исключение/ошибка в «Защиту my_method (Я)», она спрятана при визуализации шаблона (вместо этого появляется пустой вывод строки, поэтому ошибок не возникает).

Как я хочу отлаживать ошибки в 'def my_method (self)', я хотел бы включить что-то вроде глобального флага django для получения такого исключения.

в settings.py, у меня уже есть

DEBUG = True 
TEMPLATE_DEBUG = True 

я могу получить много видов исключений шаблонов, но ни когда я аккуратный метод объекта.

Что я могу сделать?

+1

У меня такая же проблема ... Я бы подумал, что это ошибка в самом джанго ... – 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

@ Эрик: "скучно"? Извините, что вам скучно. Возможно, вам стоит найти другую работу. Шутки в сторону. Единичные тесты будут работать лучше, чем это. Поиск исключения в шаблоне означает, что вы не смогли отладить вашу модель и ваши функции просмотра, используя соответствующие модульные тесты. Вам не нужно искать исключения в шаблоне, потому что есть ** лучшие ** способы, которые проще, надежнее и проще отлаживать. Извините, что это скучно. – 2010-11-30 10:52:54

0

Как и ответ С. Лотта, активируйте оболочку управления (оболочку python manage.py) и создайте соответствующий экземпляр 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. Я заметил, что string_if_invalid был пуст, несмотря на то, что он установил TEMPLATE_STRING_IF_INVALID.Это привело меня к этой части документации:

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

система шаблонов в Django была перестроена в Django 1.8, когда она получила поддержку нескольких шаблонных движков.

...

Если модуль настройки определяет ALLOWED_INCLUDE_ROOTS или TEMPLATE_STRING_IF_INVALID, включают их значения под «allowed_include_roots» и «string_if_invalid» ключи в «OPTIONS» словаря.

Таким образом, в дополнение к @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" %}.

Смежные вопросы