python python-2.7 utf-8 character-encoding jinja2

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")



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''))