Using utf-8 characters in a Jinja2 template

TL;DR:

  • Pass Unicode to template.render()
  • Encode the rendered unicode result to a bytestring before writing it to a file

This had me puzzled for a while. Because you do

index_file.write(
    template.render(index_variables)
)

in one statement, that’s basically just one line where Python is concerned, so the traceback you get is misleading: The exception I got when recreating your test case didn’t happen in template.render(index_variables), but in index_file.write() instead. So splitting the code up like this

output = template.render(index_variables)
index_file.write(output)

was the first step to diagnose where exactly the UnicodeEncodeError happens.

Jinja returns unicode whet you let it render the template. Therefore you need to encode the result to a bytestring before you can write it to a file:

index_file.write(output.encode('utf-8'))

The second error is that you pass in an utf-8 encoded bytestring to template.render() – Jinja wants unicode. So assuming your myvar contains UTF-8, you need to decode it to unicode first:

index_variables['title'] = myvar.decode('utf-8')

So, to put it all together, this works for me:

# -*- coding: utf-8 -*-

from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('myproject', 'templates'))


# Make sure we start with an utf-8 encoded bytestring
myvar="Séptimo Cine"

index_variables = {'title':''}

# Decode the UTF-8 string to get unicode
index_variables['title'] = myvar.decode('utf-8')

template = env.get_template('index.html')

with open("index_file.html", "wb") as index_file:
    output = template.render(index_variables)

    # jinja returns unicode - so `output` needs to be encoded to a bytestring
    # before writing it to a file
    index_file.write(output.encode('utf-8'))

Leave a Comment