Как увидеть исключение, сгенерированное в переменной шаблона django?
Внутри шаблона Django можно вызвать метод объекта следующим образом:
{{ my_object.my_method }}
Проблема заключается в том, что вы получаете исключение/ошибку в 'def my_method (self)', оно скрыто при визуализации шаблона (вместо этого появляется пустой вывод строки, поэтому ошибок не возникает).
Как я хочу отлаживать ошибки в "def my_method (self)", я хотел бы включить что-то вроде глобального флага django для получения такого исключения.
в settings.py, у меня уже есть
DEBUG = True
TEMPLATE_DEBUG = True
Я могу получить множество исключений шаблонов, но ни один, когда я запускаю метод объекта.
Что я могу сделать?
Ответы
Ответ 1
Вот хороший трюк, который я только что применил для этого. Поместите это в свои настройки отладки:
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 будет поднят, когда в результате анализа будет обнаружено неизвестное или недопустимое значение. Я проверил это немного (с именами переменных undefined), и он отлично работает. Я не тестировал с возвращаемыми значениями функции и т.д. Все может усложниться.
Ответ 2
Наконец, я нашел решение: я разработал шаблонный отладочный тег:
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 %}
Ответ 3
Я бы использовал Unit tests, чтобы изолировать проблему. Я знаю, что это косвенный ответ, но я считаю, что это идеальный способ решить проблему и не дать ей вернуться.
Ответ 4
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
Система Djangos была переработана в Django 1.8, когда получила поддержку нескольких механизмов шаблонов.
...
Если ваш модуль настроек определяет ALLOWED_INCLUDE_ROOTS
или TEMPLATE_STRING_IF_INVALID
, включите их значения под клавишами "ALLOWED_INCLUDE_ROOTS
" и "string_if_invalid
" в словаре "OPTIONS
".
Итак, в дополнение к трюку TemplateSyntaxError @slacy's,
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" %}
.
Ответ 5
Что я могу сделать?
Оцените метод генерации исключений в вашей функции просмотра.
def someView( request ):
.... all the normal work ...
my_object.my_method() # Just here for debugging.
return render_to_response( ... all the normal stuff... )
Вы можете удалить эту строку кода после завершения отладки.
Ответ 6
Как и ответ С. Лотта, активируйте оболочку управления (оболочку python manage.py) и создайте соответствующий экземпляр my_object, вызовите my_method. Или поставьте обработку исключений в my_method и запишите исключение.