从Django打印时出现UnicodeEncodeError

时间:2013-12-18 15:28:18

标签: python django unicode character-encoding django-views

使用python解释器

>>> print u'\xe9'
é

但如果我在Django视图中放入相同的行,我会得到

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: 
ordinal not in range(128)

为什么?

我使用的是Django 1.5.1和python 2.6.6。

一些背景......我有一个Django项目,它使用第三方模块处理一些字符串,并打印它们。当在Django之外使用模块时,它工作正常,但是当它作为Django项目的一部分使用时,它在尝试打印非ascii字符时崩溃。我并不十分关心印刷,只关心它正在做的其他事情。

1 个答案:

答案 0 :(得分:5)

Python print语句将自动将Unicode值编码为用于sys.stdout的编解码器。

在您的控制台或终端中,输出编解码器会自动从系统中获取。但是,如果您的输出重定向到文件,则使用默认编解码器ASCII

在服务器上运行的Django应用程序不能依赖输出编解码器设置为可以处理所有unicode代码点的东西。不要使用print,而是使用日志记录,并明确编码。

如果第三方库正在执行此操作,您需要联系维护人员并要求他们停止这样做。您可以使用上下文管理器将每个调用包装到该库中,该上下文管理器使用虚拟对象(具有合适的sys.stdout属性的对象)交换.encoding,但这实际上只是一个间隙测量:

from contextlib import contextmanager
from io import BytesIO
import sys

@contextmanager
def capture_stdout_unicode(codec='UTF-8'):
    output = BytesIO()
    output.encoding = codec
    orig, sys.stdout = sys.stdout, output
    try:
        yield output
    finally:
        sys.stdout = orig

然后使用它:

with capture_stdout_unicode() as out:
    api_call_that_prints()

logger.info(out.getvalue())