Как увидеть сгенерированное исключение в шаблонной переменной django? - PullRequest
16 голосов
/ 29 ноября 2010

Внутри шаблона Django можно вызывать объектный метод следующим образом:

{{ my_object.my_method }}

Проблема в том, что когда вы получаете исключение / ошибку в 'def my_method (self)', оно скрывается при рендеринге шаблона (вместо этого выводится пустая строка, поэтому ошибок не возникает).

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

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

DEBUG = True 
TEMPLATE_DEBUG = True

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

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

Ответы [ 6 ]

14 голосов
/ 21 октября 2011

Вот хороший трюк, который я только что реализовал для выполнения именно этого. Укажите это в настройках отладки:

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, когда анализатор увидит неизвестное или недопустимое значение. Я немного проверил это (с неопределенными именами переменных), и он прекрасно работает. Я не проверял возвращаемые значения функций и т. Д. Вещи могут быть сложными.

3 голосов
/ 30 ноября 2010

Наконец-то я нашел решение: я разработал шаблон отладочной метки:

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 голосов
/ 17 ноября 2015

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" %}.

2 голосов
/ 30 ноября 2010

Я бы использовал Модульные тесты , чтобы изолировать проблему.Я знаю, что это косвенный ответ, но я считаю, что это идеальный способ решить и предотвратить возвращение проблемы.

1 голос
/ 29 ноября 2010

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

Оцените метод генерации исключений в вашей функции просмотра.

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

    my_object.my_method() # Just here for debugging.

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

Вы можете удалить эту строку кода, когдазавершена отладка.

0 голосов
/ 30 ноября 2010

Аналогично ответу С. Лотта, активируйте оболочку управления (оболочка python manage.py) и создайте соответствующий экземпляр my_object, вызовите my_method.Или поместите обработку исключений в my_method и зарегистрируйте исключение.

...