10

If a template is missing deep inside the rendering of a django template, I get a exception like below.

After searching very long I found the bogus part:

 {% include form.template_name %}

form.template_name was empty in my context.

How can I find the relevant template name without searching for hours?

I am missing a traceback like for normal python code. "Normal" python tracebacks show me the file and line which contain the bug.

/home/foo_fm_d/bin/python /usr/local/pycharm-community-4.5/helpers/pycharm/utrunner.py /home/foo_fm_d/src/foo-time/foo_time/tests/unit/views/user/test_preview_of_next_days.py::EditTestCase::test_preview_of_next_days true
Testing started at 09:26 ...

Error
Traceback (most recent call last):
  File "/home/foo_fm_d/src/foo-time/foo_time/tests/unit/views/user/test_preview_of_next_days.py", line 11, in test_preview_of_next_days
    self.admin_client.get(url)
  File "/home/foo_fm_d/src/djangotools/djangotools/utils/testutils.py", line 275, in get
    response = super(Client, self).get(path, data, **extra)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/test/client.py", line 473, in get
    response = super(Client, self).get(path, data=data, **extra)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/test/client.py", line 280, in get
    return self.request(**r)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/test/client.py", line 444, in request
    six.reraise(*exc_info)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 137, in get_response
    response = response.render()
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/response.py", line 105, in render
    self.content = self.rendered_content
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/response.py", line 82, in rendered_content
    content = template.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 140, in render
    return self._render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
    return self.nodelist.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 840, in render
    bit = self.render_node(node, context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/debug.py", line 78, in render_node
    return node.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 123, in render
    return compiled_parent._render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
    return self.nodelist.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 840, in render
    bit = self.render_node(node, context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/debug.py", line 78, in render_node
    return node.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 123, in render
    return compiled_parent._render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
    return self.nodelist.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 840, in render
    bit = self.render_node(node, context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/debug.py", line 78, in render_node
    return node.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 840, in render
    bit = self.render_node(node, context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/debug.py", line 78, in render_node
    return node.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/debug.py", line 88, in render
    output = self.filter_expression.resolve(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 585, in resolve
    obj = self.var.resolve(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 735, in resolve
    value = self._resolve_lookup(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 789, in _resolve_lookup
    current = current()
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 72, in super
    return mark_safe(self.render(self.context))
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 840, in render
    bit = self.render_node(node, context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/debug.py", line 78, in render_node
    return node.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 840, in render
    bit = self.render_node(node, context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/debug.py", line 78, in render_node
    return node.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/base.py", line 840, in render
    bit = self.render_node(node, context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/debug.py", line 78, in render_node
    return node.render(context)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 166, in render
    template = get_template(template_name)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader.py", line 138, in get_template
    template, origin = find_template(template_name)
  File "/home/foo_fm_d/local/lib/python2.7/site-packages/django/template/loader.py", line 131, in find_template
    raise TemplateDoesNotExist(name)
TemplateDoesNotExist


Process finished with exit code 0

Update

My personal background: Up to now I avoid django templates since sometimes exceptions get silently ignored and tracebacks like this make the debugging process feel like wearing heavy shoes made of concrete.

I try to get get rid of my prejudices. Or least find a way how to get better error messages from templates.

Update II

I see the traceback via a unittest inside pyCharm. I don't read the result of the view. The "webbrowser" Client calls the view. I set TEMPLATE_DEBUG=True, but the result is the same.

guettli
  • 25,042
  • 81
  • 346
  • 663
  • Have you tried this: https://docs.djangoproject.com/en/1.8/ref/settings/#template-debug ? – Wtower May 26 '15 at 07:40
  • @Wtower I see the traceback via a unittest inside pyCharm. I don't read the result of the view. The "webbrowser" `Client` calls the view. I set TEMPLATE_DEBUG=True, but the result is the same. – guettli May 26 '15 at 08:12
  • Unfortunately `TEMPLATE_DEBUG=True` relies on `DEBUG=True` and that variable is automatically set to `False` when tests are run. Could you run a real server (`./manage.py runserver`) and try to reproduce it in browser with `TEMPLATE_DEBUG = DEBUG = True` in your settings ? – Weier Jun 16 '15 at 09:07
  • @Weier it is the same with TEMPLATE_DEBUG = DEBUG = True – guettli Jun 16 '15 at 12:55
  • @guettli: Did you try running that page in your browser for real (with those settings) ? That might be the way to go for debugging that error. – Weier Jun 16 '15 at 13:52
  • @Weier I updated the question, up to now it was just in a comment: I see the traceback via a unittest inside pyCharm. I don't read the result of the view. The "webbrowser" Client calls the view. I set TEMPLATE_DEBUG=True, but the result is the same. – guettli Jun 16 '15 at 18:47
  • @guettli I understood that. And as I said the debugging modes are not accessible through unit test. If you want to see a more constructive error message you should try to setup your data out of a unit test and to access your page with your browser. – Weier Jun 17 '15 at 17:57

3 Answers3

3

The reason why you don't see the usual Python stacktrace is precisely that Django templates are not Python.

It is a specific language which is itself interpreted by Python, which builds an abstract syntax tree based on the template and then evaluates this tree during the rendering phase. At this point, information associated with the source (e.g. the template file) is not accessible by default.

There is an option within Django to show more relevant information associated with exception raised while rendering the template, it is TEMPLATE_DEBUG before DJango 1.8.

See https://docs.djangoproject.com/en/1.8/ref/settings/#template-debug

This option changed with Django 1.8 and the introduction of multiple template engines as debugging information are specific to each implementation of template engine.

Edit: See also What is Django's TEMPLATE_DEBUG setting for?

Community
  • 1
  • 1
Weier
  • 1,339
  • 1
  • 10
  • 20
2

To be honest, I've always used the mechanisms the other posters suggested with a live server. However, since you are looking for a solution that might work in Jenkins and your stack shows you are going through debug.py, I had a look at the debug data there.

I notice that the template engine should add a snippet of source code for the failing part of the template in the django_template_source attribute on the Exception.

Is that present in your exception and helpful? If so, you could catch the exception and print it before failing your UT.

Peter Brittain
  • 13,489
  • 3
  • 41
  • 57
  • Thank you for reading carefully and understanding my situation. I develop web apps, but if I code backend stuff I don't use a web browser, I write unit tests. The django debug page is great, but not visible for failing tests. As I write this I get a next idea. Maybe I could start lynx or w3m and dump the html output of the django debug page to ascii .... – guettli Jun 18 '15 at 06:36
  • 1
    Yup - that would be another way to get hold of it if you can start up a test server for your content. One other thought: you could have a look at get_traceback_data in https://github.com/django/django/blob/stable/1.6.x/django/views/debug.py for further data you could extract from the Exception. – Peter Brittain Jun 18 '15 at 08:43
0

As you seem to use PyCharm, you may use the debugger which allows you to view the context of your templates (place breakpoints for that) documentation

Also, which version of Django are you using? In mine (1.8 on python3.4), there is no find_template() in the loader.py file. It may have been removed for this reason?

Btw, TemplateDoesNotExist seems to be always called with the name of the template as param, I guess for beeing able to display it in the error message, but in your case, it is empty. Maybe is it another reason for it to get hard to debug?

BriceP
  • 508
  • 2
  • 13
  • I love Python since you get a traceback if something wrong. But with django templates I get tracebacks like the above. I could use a debugger, but a good error message on the first run is very important. If the error happens during CI (we use jenkins), then I only get a ascii traceback, too. We use Django 1.6 (we will upgrade soon) and Python 2.7. – guettli Jun 11 '15 at 19:53
  • I also use the traceback as a first option for finding my errors, as it's way easier and faster, keeping the debugger for when it's is not clear enough or does not give enough info. The templates are sometimes in that case. – BriceP Jun 11 '15 at 21:43
  • Thanks to that -1, I'm no longer authorized to post answers. – BriceP Jun 12 '15 at 19:03
  • it was not me. I hardly ever down vote. I upvoted it. I hope you can post answers again. – guettli Jun 13 '15 at 20:34
  • Thank you for that! I suppose I can answer again. – BriceP Jun 15 '15 at 08:42