Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching TemplateDoesNotExist in Django

Tags:

python

django

I am trying to use the templatetag described in SO answer: https://stackoverflow.com/a/6217194/493211 in a project using Django 1.4.3 (with Python 2.7.2).

I adapted it like this:

from django import template


register = template.Library()

@register.filter
def template_exists(template_name):
    try:
        template.loader.get_template(template_name)
        return True
    except template.TemplateDoesNotExist:
        return False

So that I could use it like this in another template:

{% if 'profile/header.html'|template_exists %}        
  {% include 'profile/header.html' %}
{% else %}
  {% include 'common/header.html' %}
{% endif %}

This way, I could have avoided using solutions such as changing the order of my apps in INSTALLED_APPS.

However, it does not work. If the template does not exist, then the exception is raised within the stack/console but it is not propagated up to get_template(..) (from inside this statement), and thus not to my foolish API. Hence, this blows up in my face during the rendering. I uploaded the stacktrace to pastebin

Is this a wanted behavior from Django?

I ended up stop doing foolish things as is. But my question would remain.

like image 961
Marc-Olivier Titeux Avatar asked Jan 23 '13 13:01

Marc-Olivier Titeux


2 Answers

What about a custom tag? This doesn't provide the full functionality of include but seems to meet the needs in the question.:

@register.simple_tag(takes_context=True)
def include_fallback(context, *template_choices):
    t = django.template.loader.select_template(template_choices)
    return t.render(context)

Then in your template:

{% include_fallback "profile/header.html" "common/header.html" %}
like image 93
Geoffrey Hing Avatar answered Oct 31 '22 21:10

Geoffrey Hing


I found some kind of an answer to my question so I am posting it here for future refence.

If I use my template_exists filter like this

{% if 'profile/header.html'|template_exists %}        
  {% include 'profile/header.html' %}
{% else %}
  {% include 'common/header.html' %}
{% endif %}

and if profile/header.html does not exist, then the TemplateDoesNotExist gets strangely propagated at page load and I get a server error. However, if instead, I use this in my template:

{% with 'profile/header.html' as var_templ %}
  {% if var_templ|template_exists %}
    {% include var_templ %}
  {% else %}
    {% include 'common/header.html' %}
  {% endif %}
{% endwith %}

Then, it works like a charm!

Obviously, I could have used

django.template.loader.select_template(['profile/header.html','common/header.html']) 

in the view (from this SO answer). But I am using a CBV which I wanted to keep rather generic and this was called from the main template. And also I thought it would be nice to have my site working if this apps goes down for whatever reason. If this seems silly to you, please leave a comment (or yet a better answer).

like image 31
Marc-Olivier Titeux Avatar answered Oct 31 '22 22:10

Marc-Olivier Titeux