在Jinja2模板中使用utf-8字符

34 投票
3 回答
51627 浏览
提问于 2025-04-17 20:50

我正在尝试在使用Jinja2渲染模板时使用utf-8字符。我的模板大概是这样的:

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

标题变量是这样设置的:

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

现在,问题是myvar是从消息队列读取的消息,里面可能包含一些特殊的utf-8字符(比如“Séptimo Cine”)。

渲染后的模板看起来像这样:

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

而我希望它能变成:

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

我做了几个测试,但始终无法解决这个问题。

  • 我尝试过不使用.encode("utf8")来设置标题变量,但出现了一个异常(ValueError: Expected a bytes object, not a unicode object),所以我猜测最初的消息是unicode格式的。

  • 我使用chardet.detect来检测消息的编码(结果是“ascii”),然后进行了以下操作:myvar.decode("ascii").encode("cp852"),但标题仍然没有正确渲染。

  • 我还确保我的模板是一个UTF-8文件,但这并没有改变什么。

有没有什么好的办法可以解决这个问题?

3 个回答

-6

在你的脚本开头加上以下几行代码,这样就能正常工作了,不需要做其他任何修改:

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

import sys
reload(sys)
sys.setdefaultencoding("utf-8")
5

试着把你的渲染命令改成这样...

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

Jinja2的文档上说:“这将返回渲染后的模板,格式是unicode字符串。”

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

希望这能帮到你!

43

简而言之:

  • 把 Unicode 传给 template.render()
  • 在把结果写入文件之前,把渲染出来的 Unicode 结果编码成字节串

这让我困惑了一段时间。因为你在一行代码里做了

index_file.write(
    template.render(index_variables)
)

这基本上在 Python 中就是一行代码,所以你看到的错误信息可能会让人误解:我在重现你的测试案例时遇到的异常并不是在 template.render(index_variables) 里,而是在 index_file.write() 里。因此,把代码分开像这样

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

是诊断 UnicodeEncodeError 出现位置的第一步。

Jinja 在渲染模板时会返回 Unicode。因此,在写入文件之前,你需要把结果编码成字节串:

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

第二个错误是你把一个 utf-8 编码的字节串传给了 template.render() - Jinja 需要的是 Unicode。所以假设你的 myvar 包含 UTF-8,你需要先把它解码成 Unicode:

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

所以,综合起来,这样做对我有效:

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

撰写回答