usar plantillas para examples descargar bootstrap python django django-templates

python - para - plantillas django



¿Cómo ver la excepción generada en la variable de plantilla django? (6)

Dentro de una plantilla de Django, uno puede llamar a un método de objeto como este:

{{ my_object.my_method }}

El problema es cuando obtienes una excepción / error en ''def my_method (self)'', se oculta al procesar la plantilla (en su lugar, hay un resultado de cadena vacía, por lo que no aparece ningún error).

Como quiero depurar lo que está mal en ''def my_method (self)'', me gustaría activar algo así como una bandera global django para recibir esa excepción.

en settings.py, ya tengo

DEBUG = True TEMPLATE_DEBUG = True

Puedo recibir muchos tipos de excepciones de plantilla, pero ninguna cuando trigloco un método de objeto.

Que puedo hacer ?


Que puedo hacer ?

Evalúa el método de generación de excepciones en tu función de vista.

def someView( request ): .... all the normal work ... my_object.my_method() # Just here for debugging. return render_to_response( ... all the normal stuff... )

Puede eliminar esa línea de código cuando termine de depurar.


De forma similar a la respuesta de S. Lott, active el shell de gestión (shell python manage.py) y cree la instancia apropiada de my_object, llame a my_method. O ponga el manejo de excepciones en my_method y registre la excepción.


Usaría pruebas unitarias para aislar el problema. Sé que esta es una respuesta indirecta, pero creo que esta es la forma ideal de resolver y evitar que el problema vuelva.


Finalmente encontré una solución: desarrollé una etiqueta de depuración de plantilla:

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])

Entonces ahora en mi plantilla simplemente reemplazo

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


Aquí hay un buen truco que acabo de implementar para hacer exactamente esto. Pon esto en tu configuración de depuración:

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")

Esto causará que se genere una TemplateSyntaxError cuando el análisis ve un valor desconocido o no válido. He probado esto un poco (con nombres de variable indefinidos) y funciona muy bien. No he probado con valores de retorno de función, etc. Las cosas podrían complicarse.


TEMPLATE_STRING_IF_INVALID no funciona para mí. Una solución rápida es abrir env/lib64/python2.7/site-packages/django/template/base.py , buscar except Exception y lanzar una print e dentro de él (suponiendo que está utilizando manage.py runserver y puede ver imprimir salida).

Sin embargo, algunas líneas abajo son current = context.template.engine.string_if_invalid . Noté que string_if_invalid estaba vacío a pesar de haber configurado TEMPLATE_STRING_IF_INVALID . Esto me lleva a esta parte de los documentos:

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

El sistema de plantillas de Django fue revisado en Django 1.8 cuando obtuvo soporte para múltiples motores de plantillas.

...

Si su módulo de configuración define ALLOWED_INCLUDE_ROOTS o TEMPLATE_STRING_IF_INVALID , incluya sus valores bajo las allowed_include_roots '' allowed_include_roots '' y '' string_if_invalid '' en el diccionario '' OPTIONS ''.

Entonces, además del truco TemplateSyntaxError de @ slacy ,

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")

también necesita definir string_if_invalid siguiente manera

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, ...

Directamente, esto encontró un montón de problemas que tenía que ni siquiera sabía. Realmente debería estar habilitado por defecto. Para resolver etiquetas y filtros que esperan fallar silenciosamente, lancé condicionales a su alrededor:

{% if obj.might_not_exist %} {{ obj.might_not_exist }} {% endif %}

Aunque sospecho que esto solo funciona porque el {% if %} falla silenciosamente. Otro enfoque podría ser crear un filtro hasattr : {% if obj|hasattr:"might_not_exist" %} .