34

I'm using Django templates in a non-Django project and I want to make sure that my templates contain no references to variables that are not in context and for that I need Django template renderer to raise an error when it sees {{ non_existent_variable }} when there is no non_existent_variable in Context.

TEMPLATE_STRING_IF_INVALID could be set to something and then we could check that this something is not in the rendered template, but that is not elegant at all.

Can I somehow without too much work override the way Context swallows missing key errors?

jbasko
  • 7,028
  • 1
  • 38
  • 51
  • 1
    http://djangosnippets.org/snippets/646/ – catherine Mar 09 '13 at 15:09
  • I don't see a compelling reason to use the Django template engine outside a Django project. Django template engine was designed to be "web-designer-proof", and this behavior is just one of the compromises made. Have you heard of Jinja2? – Paulo Scardine Mar 09 '13 at 15:16
  • @PauloScardine thanks, i had heard about it, but never cared to check it out. Will try to replace Django templates then. – jbasko Mar 09 '13 at 15:20
  • @zilupe: You will not regret, Jinja is similar enough you can leverage your Django template knowledge but is more flexible and performs better. See http://jinja.pocoo.org/docs/api/#undefined-types for information about behavior on Undefined context variables. – Paulo Scardine Mar 09 '13 at 15:25
  • 1
    @pauloscardine django templates have disadvantages, but some of them are intentional. Using standard django templates means you can use more standard django libraries, and that very little business logic will be in the template (which is what you want). We actually just switched from jinja to django templates for that very reason. – Catskul Nov 28 '14 at 21:24
  • @Catskul: are you using django templates at non-django projects like the OP? – Paulo Scardine Nov 28 '14 at 22:25
  • @PauloScardine, no, just wanted to make sure the reason for django-templates disadvantages was spoken for – Catskul Nov 28 '14 at 22:38
  • Does this answer your question? [Show undefined variable errors in Django templates?](https://stackoverflow.com/questions/4300442/show-undefined-variable-errors-in-django-templates) – Flimm Nov 26 '21 at 15:12

2 Answers2

26

There is a Django Snippet which provides a solution:

# settings.py
class InvalidVarException(object):
    def __mod__(self, missing):
        try:
            missing_str=unicode(missing)
        except:
            missing_str='Failed to create string representation'
        raise Exception('Unknown template variable %r %s' % (missing, missing_str))
    def __contains__(self, search):
        if search=='%s':
            return True
        return False

TEMPLATE_DEBUG=True
TEMPLATE_STRING_IF_INVALID = InvalidVarException()
MichaelJones
  • 1,336
  • 2
  • 12
  • 22
catherine
  • 22,492
  • 12
  • 61
  • 85
  • This is useful but it won't catch a missing variable in `{% if not i_do_not_exist %}`. Is there a fix? – user Jan 24 '15 at 13:59
  • 2
    This is great, thank you. Note that in Django 1.8+, you need to set `OPTIONS['debug']` and `OPTIONS['string_if_invalid']` instead. But is there a way to make it work in `missing_var|default:"foo"` scenarios? It seems this raises before `default` has a chance to do it's thing. – Maik Hoepfel May 24 '16 at 11:26
  • 2
    I tried this solution with Django 1.11, using `string_if_invalid`, and I got this error when running the server: `?: (templates.E002) 'string_if_invalid' in TEMPLATES OPTIONS must be a string but got: (InvalidVarException).` – David Dahan May 06 '17 at 15:44
  • In Django 1.11+ I just set `OPTIONS['debug'] = True` and `OPTIONS['string_if_invalid'] = 'INVALID_VARIABLE_REFERENCED: %s.'` in the `TEMPLATES` variable. When an error occurs, then I get on the template something like: `INVALID_VARIABLE_REFERENCED: wrong.variable_name.`. I found it on https://docs.djangoproject.com/en/1.10/ref/templates/api/#how-invalid-variables-are-handled – Ruben Alves Sep 20 '19 at 09:22
  • On 3.2, it doesn't let you use a non-string like `InvalidVarException` for `string_if_invalid` – Dustin Wyatt Sep 13 '21 at 17:45
0

You can easily switch template backend to jinja2 to get this.

Step 0: add jinja2 to your Pipfile or requirements.txt

Step 1: in settings.py change TEMPLATES to look like this:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'APP_DIRS': True,
        'OPTIONS': {
            'undefined': jinja2.StrictUndefined
        },
    },
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        ...

Step 2: rename your templates directory to jinja2

Step 3: (maybe not needed, depends on what you use in templates) update your templates according to https://jinja.palletsprojects.com/en/2.10.x/switching/#django

Michel Samia
  • 4,273
  • 2
  • 24
  • 24