Uso de caracteres utf-8 en una plantilla Jinja2


Estoy tratando de usar caracteres utf-8 al renderizar una plantilla con Jinja2. Así es como se ve mi plantilla:

<!DOCTYPE HTML>
<html manifest="" lang="en-US">
<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
...

La variable title se establece algo como esto:

index_variables = {'title':''}
index_variables['title'] = myvar.encode("utf8")

template = env.get_template('index.html')
index_file = open(preview_root + "/" + "index.html", "w")

index_file.write(
    template.render(index_variables)
)
index_file.close()

Ahora, el problema es que myvar es un mensaje leído de una cola de mensajes y puede contener esos caracteres especiales utf8 (ej. "Séptimo Cine").

La plantilla renderizada se ve algo así como:

...
    <title>S\u00e9ptimo Cine</title>
...

Y quiero que sea:

...
    <title>Séptimo Cine</title>
...

He hecho varias pruebas, pero no puedo hacer que esto funcione.

  • He intentado establecer la variable title sin .encode ("utf8") , pero arroja una excepción (ValueError: Se espera un objeto bytes, no un objeto unicode ), por lo que mi conjetura es que el mensaje inicial es unicode

  • He usado chardet.detect para obtener la codificación del mensaje (es "ascii"), luego hizo lo siguiente: myvar.decodificar ("ascii").codificar ("cp852"), pero el título todavía no se representa correctamente.

  • También me aseguré de que mi plantilla sea un archivo UTF-8, pero no hizo ninguna diferencia.

¿Alguna idea sobre cómo hacer esto?

Author: alex.ac, 2014-03-05

4 answers

TL; DR: {[13]]}

  • Pase Unicode a template.render()
  • Codifique el resultado unicode renderizado a una bytestring antes de escribirlo en un archivo

Esto me dejó perplejo por un tiempo. Porque lo haces

index_file.write(
    template.render(index_variables)
)

En una declaración, eso es básicamente solo una línea en lo que respecta a Python, por lo que el rastreo que obtienes es engañoso: La excepción que obtuve al recrear tu caso de prueba no sucedió en template.render(index_variables), sino en index_file.write() en su lugar. Así que dividiendo el código como esto

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

Fue el primer paso para diagnosticar dónde ocurre exactamente el UnicodeEncodeError.

Jinja devuelve unicode cuando se le permite renderizar la plantilla. Por lo tanto, necesita codificar el resultado a una bytestring antes de poder escribirlo en un archivo:

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

El segundo error es que pasas un utf-8 codificado bytestring a template.render() - Jinja quiere unicode . Así que asumiendo que su myvar contiene UTF-8, primero necesita decodificarlo a unicode:

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

Así que, para decirlo todo juntos, esto funciona para mí:

# -*- 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", "w") 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'))
 29
Author: Lukas Graf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-04 20:47:48

Intente cambiar su comando de renderizado a esto...

template.render(index_variables).encode( "utf-8" )

La documentación de Jinja2 dice "Esto devolverá la plantilla renderizada como cadena unicode."

Http://jinja.pocoo.org/docs/api/?highlight=render#jinja2.Template.render

Espero que esto ayude!

 5
Author: Andrew Kloos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-04 20:56:01

Y si nada funciona porque tienes una mezcla de idiomas-como en mi caso -, simplemente reemplaza "utf-8" por "utf-16"

Todas las opciones de codificación aquí:

Https://docs.python.org/2.4/lib/standard-encodings.html

 0
Author: alfonso olivas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-17 08:56:52

Agregue las siguientes líneas al principio de su script y funcionará bien sin más cambios:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
reload(sys)
sys.setdefaultencoding("utf-8")
 -3
Author: asmaier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-05 20:16:16