python - Usar caracteres utf-8 en una plantilla Jinja2
python-2.7 character-encoding (4)
Estoy tratando de usar caracteres utf-8 cuando renderizo 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 de título se establece de esta manera:
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 (por ejemplo, "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 realizado varias pruebas pero no puedo hacer que esto funcione.
He intentado establecer la variable de título sin .encode ("utf8") , pero arroja una excepción ( ValueError: se esperaba un objeto de bytes, no un objeto de Unicode ), así que supongo que el mensaje inicial es unicode
He usado chardet.detect para obtener la codificación del mensaje (es "ascii"), y luego hice lo siguiente: myvar.decode ("ascii"). Encode ("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 marcó la diferencia.
¿Alguna idea sobre cómo hacer esto?
Agregue las siguientes líneas al comienzo de su script y funcionará bien sin ningún otro cambio:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Intenta cambiar tu comando de renderizado a este ...
template.render(index_variables).encode( "utf-8" )
La documentación de Jinja2 dice "Esto devolverá la plantilla representada como cadena unicode".
http://jinja.pocoo.org/docs/api/?highlight=render#jinja2.Template.render
¡Espero que esto ayude!
TL; DR:
- Pase Unicode a
template.render()
- Codifique el resultado del Unicode renderizado en una cadena de bytes 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 afirmación, básicamente se trata de una sola línea en Python, por lo que el rastreo que obtiene es engañoso: la excepción que obtuve al template.render(index_variables)
su caso de prueba no ocurrió en template.render(index_variables)
, sino en index_file.write()
en lugar. Así que dividiendo el código como este
output = template.render(index_variables)
index_file.write(output)
fue el primer paso para diagnosticar dónde ocurre exactamente el UnicodeEncodeError
.
Jinja devuelve unicode si dejas que renderice la plantilla. Por lo tanto, debe codificar el resultado en una cadena de bytes antes de poder escribirlo en un archivo:
index_file.write(output.encode(''utf-8''))
El segundo error es que pasas una cadena de bytes codificada en utf-8
a template.render()
- Jinja quiere unicode . Entonces, suponiendo que su myvar
contiene UTF-8, primero debe decodificarlo en Unicode:
index_variables[''title''] = myvar.decode(''utf-8'')
Entonces, para decirlo todo, 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''))
Y si nada funciona porque tienes una combinación de idiomas, como en mi caso, simplemente reemplaza "utf-8" por "utf-16"
Todas las opciones de codificación aquí: