11👍
According to the django documentation,
undefined variables are treated as ”(empty string) by default. While in if for regroup, it’s None.
If you are going to identify the variable undefined, change TEMPLATE_STRING_IF_INVALID in settings.
‘%s’ makes the invalid variable to be rendered as its variable name, in this way, u can identify easily.
how-invalid-variables-are-handled
25👍
Put this in your debug settings:
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")
This should raise an error when the template engine sees or finds an undefined value.
- [Django]-Find Monday's date with Python
- [Django]-How to catch the MultipleObjectsReturned error in django
- [Django]-How to run cloned Django project?
6👍
How to log a warning on undefined variable in a template
It seems that Django relies on undefined variables being a simple empty string. So instead of changing this behaviour or making it throw an exception, let’s keep it the same but have it log a warning instead!
In your settings.py
file:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# ...
'OPTIONS': {
# ...
'string_if_invalid': InvalidStringShowWarning("%s"),
},
}
]
(string_if_invalid
replaces TEMPLATE_STRING_IF_INVALID
in newer Django versions.)
And further up, you’ll need to define the InvalidStringShowWarning
class, making it behave while logging a warning:
class InvalidStringShowWarning(str):
def __mod__(self, other):
import logging
logger = logging.getLogger(__name__)
logger.warning("In template, undefined variable or unknown value for: '%s'" % (other,))
return ""
def __bool__(self): # if using Python 2, use __nonzero__ instead
# make the template tag `default` use its fallback value
return False
You should be able to see the warning in the output of python manage.py runserver
.
- [Django]-Django admin – how to make "inlines" collapsible?
- [Django]-Django, filter by specified month and year in date range
- [Django]-Django 1.10.1 'my_templatetag' is not a registered tag library. Must be one of:
6👍
Finding template variables that didn’t exist in the context was important to me as several times bugs made it into production because views had changed but templates had not.
I used this technique, implemented in manage.py
, to achieve the effect of breaking tests when template variables not found in the context were used. Note that this technique works with for
loops and if
statements and not just {{ variables }}
.
import sys
# sometimes it's OK if a variable is undefined:
allowed_undefined_variables = [
'variable_1',
'variable_2',
]
if 'test' in sys.argv:
import django.template.base as template_base
old_resolve = template_base.Variable.resolve
def new_resolve(self, context):
try:
value = old_resolve(self, context)
except template_base.VariableDoesNotExist as e:
# if it's not a variable that's allowed to not exist then raise a
# base Exception so Nodes can't catch it (which will make the test
# fail)
if self.var not in allowed_undefined_variables:
raise Exception(e)
# re-raise the original and let the individual Nodes deal with it
# however they'd like
raise e
return value
template_base.Variable.resolve = new_resolve
- [Django]-Use only some parts of Django?
- [Django]-Django Testing – check messages for a view that redirects
- [Django]-How to properly use the "choices" field option in Django
3👍
I believe that’s a major oversight on Django’s part and the primary reason I prefer not to use their default template engine. The sad truth is that, at least for now (Django 1.9), you can’t achieve this effect reliably.
-
You can make Django raise an exception when
{{ undefined_variable }}
is encountered – by using “the hack” described in slacy’s answer. -
You can’t make Django raise the same exception on
{% if undefined_variable %}
or{% for x in undefined_variable %}
etc. “The hack” doesn’t work in such cases. -
Even in cases in which you can, it is strongly discouraged by Django authors to use this technique in production environment. Unless you’re sure you don’t use Django’s built-in templates in your app, you should use “the hack” only in
DEBUG
mode.
However, if you’re stuck with Django’s templates for now, I would recommend to use slacy’s answer, just make sure you’re in DEBUG
mode.
- [Django]-Using django-rest-interface
- [Django]-Unit testing with django-celery?
- [Django]-Django.db.utils.OperationalError: fe_sendauth: no password supplied
2👍
Read up on how invalid variable are handled in templates. Basically, just set TEMPLATE_STRING_IF_INVALID to something in your settings.py.
TEMPLATE_STRING_IF_INVALID = "He's dead Jim! [%s]"
- [Django]-Is this the right way to do dependency injection in Django?
- [Django]-Start celery worker throws "no attribute 'worker_state_db'"
- [Django]-What's the best way to store a phone number in Django models?
1👍
I am use next:
import logging
from django.utils.html import format_html
from django.utils.safestring import mark_safe
class InvalidTemplateVariable(str):
"""
Class for override output that the Django template system
determinated as invalid (e.g. misspelled) variables.
"""
# styles for display message in HTML`s pages
styles = mark_safe('style="color: red; font-weight: bold;"')
def __mod__(self, variable):
"""Overide a standart output here."""
# access to current settings
from django.conf import settings
# display the message on page in make log it only on stage development
if settings.DEBUG is True:
# format message with captured variable
msg = 'Attention! A variable "{}" does not exists.'.format(variable)
# get logger and make
logger = self.get_logger()
logger.warning(msg)
# mark text as non-escaped in HTML
return format_html('<i {}>{}</i>', self.styles, msg)
# on production it will be not displayed
return ''
def get_logger(self):
"""Create own logger with advanced error`s details."""
logger = logging.getLogger(self.__class__.__name__)
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
Usage in settings file (by default it settings.py):
TEMPLATES = [
{
......
'OPTIONS': {
.....................
'string_if_invalid': InvalidTemplateVariable('%s'),
.....................
},
},
]
or directly
TEMPLATES[0]['OPTIONS']['string_if_invalid'] = InvalidTemplateVariable('%s')
A result if DEBUG = True:
On page
In console
> System check identified 1 issue (0 silenced). October 03, 2016 -
> 12:21:40 Django version 1.10.1, using settings 'settings.development'
> Starting development server at http://127.0.0.1:8000/ Quit the server
> with CONTROL-C. 2016-10-03 12:21:44,472 - InvalidTemplateVariable -
> WARNING - Attention! A variable "form.media" does not exists.
- [Django]-Django Reverse Accessor Clashes
- [Django]-Django – form has no errors but form.is_valid() doesn't validate
- [Django]-Django: manually create imagefield in model from existing file on server
0👍
You can use the pytest-django setting FAIL_INVALID_TEMPLATE_VARS
The invaild vars get checked if pytest executes the code.
[pytest]
DJANGO_SETTINGS_MODULE = mysite.settings
FAIL_INVALID_TEMPLATE_VARS = True
- [Django]-Location of Django logs and errors
- [Django]-Celery task with a time_start attribute in 1970
- [Django]-Django – ordering queryset by a calculated field
-4👍
If there is a undefined variable in templates, django won’t tell you.
You can print this variable in view.
- [Django]-Empty Label ChoiceField Django
- [Django]-How can I get the timezone aware date in django?
- [Django]-What does request.user refer to in Django?