Iām aware that I could predefine every possible variable in context to avoid that. But Iām reusing a lot of templates by even more views whereby the variables are used as switch to either show content or not (load the content related template with include to be more specific). Making any change on a template (e.g. adding a switch) would cause a lot of work (preset added switch in any view using this template).
Further online reading let me guess, that Iām using a āgoodā way by checking variable in template with if-condition but how to avoid the raised ValueDoesNotExist error?
<opinion>
One of the real strengths and benefits of the Django template language is that you donāt need to do that in the general case.
Some people disagree, and I can appreciate their concerns.
But I have found that the ability to not provide every variable in a context allows for more generic and flexible templates to be used, reducing both the size and number of templates needed for a project. <opinion>
If you find those messages bothersome, create a filter for your logging configuration to filter them out. (The logger would be ādjango.templateā.)
But these types of log messages should be considered āroutineā or ānormalā under most circumstances.
Thanks for pointing out that this is an intentional behaviour. Itās really annoying because this behaviour extremely bloats up my debug files due to the way Iām checking for existence. For the moment I increased the logging level for ādjango.templateā to WARNING, but I consider adding/creating a tag to explicitly check existence of variables in templates. With this I could keep working in DRY principles and having an explicit check which would be the most pythonic way I think.
# extended part of LOGGING in settings.py
# [...]
'loggers': {
'django': {
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
'django.template': { # avoid log of missing context variables as DEBUG messages
'handlers': ['file'],
'level': 'WARNING',
'propagate': False,
},
},
# [...]
I share your opinion about the flexibility of templates by not providing every possible variable in a context and I was expecting that there must be another built-in way to check for existence than manipulating logging.
First, you have what I consider to be the common case - if a template variable does not exist in the context, render nothing. However, you may also have the case where a variable that doesnāt exist could be an indication of a problem, and so you may want that information logged.
<opinion>
Determining whether you want that information kept, what is to be logged, and where and how it is to be stored seems to me to be exactly the type of thing the logging configuration is designed to handle.
I canāt think of a better or more suitable place for it. </opinion>
Side note, there is a difference between:
and {{ var_one }}
in that the if condition will not render a āFalsyā value where the second version will.
I was thinking, as you stated, that checking a context variable for existence is a common case and it might be implemented in django. Well, it is implemented to be precise but itās ever throwing errors at DEBUG level when a variable does not exist and I was expecting that there is a more explicit way than filtering logs or pushing up log level.
Get me right, this is neither an offense nor a complain. I was just wondering if there is a built-in way to check for existence in templates without having internally thrown errors. But of course django cannot catch every use case or every favor. Iām able to implement this for myself. In this case itās not that much work (at least implementing the tag, altering the templates may take some time, but this is based on my design decision how I use templates and is nothing anyone who contributed to django is responsible for).
Yes, Iām aware of it. Thatās why I mentioned that it would be a solution (but not for me) to set all possible context variables to None or False which are used as switch to show content. Errors are thrown in both cases (when checked in a condition and when directly used), of course.
<conjecture>
Iām going to guess that not raising the exception could cause other problems within the rendering engine. (Iām thinking in terms of how the parsed template nodes are handled, and the potential interrelationship between those variables and other chained references and/or filters.) It seems possible to me that having something like {{ var.invalid.something_else }} is just going to throw a different exception if invalid does not exist - and the processing of that node isnāt short-circuited at that point. </conjecture>
Agreed. At this point Iām thinking about this as a āthought experimentā or an āacademic exerciseā. i.e., What would happen if the resolver didnāt throw an exception at that location, ?
100% spot-on here. You can see where this is done in django.template.base.Variable._resolve_lookup method.
In theory, you do have a couple different ways to work around this. Implementing a custom tag (e.g., {% var %} ?) might be one way to do it. (You could even create a custom loader that parsed the {{ .. }} identifier and caused that to be interpreted as {% ... %} instead.) Another would be to monkey-patch the Variable._resolve_lookup method.
Itās just that anything along those lines seems like a lot more work, with uncertain side-effects, than configuring the logger.
After learning that there is no built-in way, the easiest and most predictable way for me seems to use a simple_tag like
# custom_tags.py, NOT TESTED
@register.simple_tag(takes_context=True)
def exists(context, key):
return key in context
# template.html, NOT TESTED
{% exists 'var' as var_exists %}
{% if var_exists %}
{{ var }}
{% endif %}
I did not tested it so maybe itās not working. But every other way (monkey patching, custom loader, ā¦) may have side effects which Iām not aware of.
It would be better when this would be usable like
# abstract code, NOT WORKING
{% if var|exists %}
{{ var }}
{% endif %}
But I didnāt take much effort to check how to get context into a filter or if this is even possible.
I agree but configuring the logger is a quite implicit way of avoidance. For me itās more clear when I can see already in the template that a variable might not exist, even this is only my personal favor.