﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
17664	{% if %} template tag silences exceptions inconsistently	Tai Lee		"This buggy behaviour took me a while to track down. I hope I can explain it clearly.

Given a `QuerySet` with invalid ordering (and possibly other conditions) that should raise an exception when evaluated, `{% if qs %}` will raise the exception while `{% if not qs %}` will silence it and leave `qs` as if it were simply empty on subsequent access in the template.

First, the exception is silenced and the queryset becomes empty:

{{{
>>> from django.contrib.auth.models import User
>>> from django.template import Template, Context
>>> Template('count: {{ qs.count }}, empty: {% if not qs %}yes{% else %}no{% endif %}, qs: {{ qs }}, count: {{ qs.count }}').render(Context({'qs': User.objects.order_by('invalid_field')}))
u'count: 98, empty: no, qs: [], count: 0'
}}}

And now if we swap the `{% if %}` around a bit, we get an exception:

{{{
>>> Template('count: {{ qs.count }}, empty: {% if qs %}no{% else %}yes{% endif %}, qs: {{ qs }}, count: {{ qs.count }}').render(Context({'qs': User.objects.order_by('invalid_field')}))
Traceback (most recent call last):
  File ""<console>"", line 1, in <module>
  File ""/Users/mrmachine/django/template/base.py"", line 139, in render
    return self._render(context)
  File ""/Users/mrmachine/django/template/base.py"", line 133, in _render
    return self.nodelist.render(context)
  File ""/Users/mrmachine/django/template/base.py"", line 819, in render
    bits = []
  File ""/Users/mrmachine/django/template/debug.py"", line 73, in render_node
    return node.render(context)
  File ""/Users/mrmachine/django/template/defaulttags.py"", line 273, in render
    if var:
  File ""/Users/mrmachine/django/db/models/query.py"", line 129, in __nonzero__
    iter(self).next()
  File ""/Users/mrmachine/django/db/models/query.py"", line 117, in _result_iter
    self._fill_cache()
  File ""/Users/mrmachine/django/db/models/query.py"", line 855, in _fill_cache
    self._result_cache.append(self._iter.next())
  File ""/Users/mrmachine/django/db/models/query.py"", line 288, in iterator
    for row in compiler.results_iter():
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 704, in results_iter
    for rows in self.execute_sql(MULTI):
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 750, in execute_sql
    sql, params = self.as_sql()
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 64, in as_sql
    ordering, ordering_group_by = self.get_ordering()
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 364, in get_ordering
    self.query.model._meta, default_order=asc):
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 393, in find_ordering_name
    opts, alias, False)
  File ""/Users/mrmachine/django/db/models/sql/query.py"", line 1289, in setup_joins
    ""Choices are: %s"" % (name, "", "".join(names)))
FieldError: Cannot resolve keyword 'invalid_field' into field. Choices are: date_joined, email, first_name, groups, id, is_active, is_staff, is_superuser, last_login, last_name, logentry, password, user_permissions, username
}}}

I think the `{% if %}` tag needs to be a little less quick to silence exceptions here, but there is also a problem with the way a `QuerySet` will appear to be empty after an exception is raised.

First, we get an exception:

{{{
>>> qs = User.objects.order_by('abc')
>>> list(qs)
Traceback (most recent call last):
  File ""<console>"", line 1, in <module>
  File ""/Users/mrmachine/django/db/models/query.py"", line 86, in __len__
    self._result_cache.extend(self._iter)
  File ""/Users/mrmachine/django/db/models/query.py"", line 288, in iterator
    for row in compiler.results_iter():
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 704, in results_iter
    for rows in self.execute_sql(MULTI):
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 750, in execute_sql
    sql, params = self.as_sql()
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 64, in as_sql
    ordering, ordering_group_by = self.get_ordering()
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 364, in get_ordering
    self.query.model._meta, default_order=asc):
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 393, in find_ordering_name
    opts, alias, False)
  File ""/Users/mrmachine/django/db/models/sql/query.py"", line 1289, in setup_joins
    ""Choices are: %s"" % (name, "", "".join(names)))
FieldError: Cannot resolve keyword 'abc' into field. Choices are: date_joined, email, first_name, groups, id, is_active, is_staff, is_superuser, last_login, last_name, logentry, password, user_permissions, username
}}}

Then, we appear to have an empty queryset:

{{{
>>> list(qs)
[]
}}}

Even though the `Query` is still invalid:

{{{
>>> print qs.query
Traceback (most recent call last):
  File ""<console>"", line 1, in <module>
  File ""/Users/mrmachine/django/db/models/sql/query.py"", line 167, in __str__
    sql, params = self.sql_with_params()
  File ""/Users/mrmachine/django/db/models/sql/query.py"", line 175, in sql_with_params
    return self.get_compiler(DEFAULT_DB_ALIAS).as_sql()
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 64, in as_sql
    ordering, ordering_group_by = self.get_ordering()
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 364, in get_ordering
    self.query.model._meta, default_order=asc):
  File ""/Users/mrmachine/django/db/models/sql/compiler.py"", line 393, in find_ordering_name
    opts, alias, False)
  File ""/Users/mrmachine/django/db/models/sql/query.py"", line 1289, in setup_joins
    ""Choices are: %s"" % (name, "", "".join(names)))
FieldError: Cannot resolve keyword 'abc' into field. Choices are: date_joined, email, first_name, groups, id, is_active, is_staff, is_superuser, last_login, last_name, logentry, password, user_permissions, username
}}}

I think that this only becomes a problem when the exception is mistakenly silenced or not handled correctly, as in the example with the `{% if %}` tag. In most circumstances, the exception would be raised and further processing would not occur.

However, I think we should still look at the possibility of NOT caching results when a queryset fails to evaluate in this way. I do not think it is appropriate to equate an invalid queryset with an empty one. If an exception is raised once when trying to evaluate a queryset, the exception should be cached or the queryset should be re-evaluated when it is accessed again.
"	Bug	new	Template system	dev	Normal		smart if tag queryset exception silenced	krzysiumed@… Ülgen Sarıkavak Giannis Terzopoulos	Accepted	0	0	0	0	0	0
