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?
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'))
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!
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í:
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")
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