从Django打印时出现UnicodeEncodeError

sko*_*oll 2 python django unicode character-encoding django-views

使用python解释器

>>> print u'\xe9'
é
Run Code Online (Sandbox Code Playgroud)

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

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

这是为什么?

我正在使用Django 1.5.1和python 2.6.6.

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

Mar*_*ers 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
Run Code Online (Sandbox Code Playgroud)

然后用这个:

with capture_stdout_unicode() as out:
    api_call_that_prints()

logger.info(out.getvalue())
Run Code Online (Sandbox Code Playgroud)