【问题标题】:Decoding utf-8 in Django while using unicode_literals in Python 2.7在 Python 2.7 中使用 unicode_literals 时在 Django 中解码 utf-8
【发布时间】:2012-08-30 14:00:38
【问题描述】:

我正在使用 Django 来管理 Postgres 数据库。我有一个值存储在代表西班牙(马拉加)的一个城市的数据库中。我的 Django 项目通过将 from __future__ import unicode_literals 放在我创建的每个文件的开头来对所有内容使用 unicode 字符串。

我需要从数据库中提取城市信息并使用XML 请求将其发送到另一台服务器。一路上有日志记录,以便我可以观察数据流。当我尝试记录城市的值时,我得到以下回溯:

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

这是我用来记录我传递的值的代码。

def createXML(self, dict):
    """
    ..  method:: createXML()

        Create a single-depth XML string based on a set of tuples

        :param dict: Set of tuples (simple dictionary)
    """

    xml_string = ''
    for key in dict:
        self.logfile.write('\nkey = {0}\n'.format(key))
        if (isinstance(dict[key], basestring)):
            self.logfile.write('basestring\n')
            self.logfile.write('value = {0}\n\n'.format(dict[key].decode('utf-8')))
        else:
            self.logfile.write('value = {0}\n\n'.format(dict[key]))

        xml_string += '<{0}>{1}</{0}>'.format(key, dict[key])

    return xml_string

我基本上将所有信息保存在一个简单的字典中,并使用此函数生成一个XML 格式化字符串 - 这超出了本问题的范围。

我得到的错误让我想知道数据库中实际保存的是什么。我已经验证该值是utf-8 编码的。我创建了一个简单的脚本来从数据库中提取值,对其进行解码并将其打印到屏幕上。

from __future__ import unicode_literals
import psycopg2
# Establish the database connection
try:
    db = psycopg2.connect("dbname = 'dbname' \
                           user = 'user' \
                           host = 'IP Address' \
                           password = 'password'")
    cur = db.cursor()
except:
    print "Unable to connect to the database."

# Get database info if any is available
command = "SELECT state FROM table WHERE id = 'my_id'"
cur.execute(command)
results = cur.fetchall()

state = results[0][0]
print "my state is {0}".format(state.decode('utf-8'))

结果:my state is Málaga

在 Django 中,我正在执行以下操作来创建 HTTP 请求:

## Create the header
http_header = "POST {0} HTTP/1.0\nHost: {1}\nContent-Type: text/xml\nAuthorization: Basic {2}\nContent-Length: {3}\n\n"
req = http_header.format(service, host, auth, len(self.xml_string)) + self.xml_string

谁能帮我纠正问题,以便我可以将此信息写入数据库并能够创建req 字符串以发送到其他服务器?

我是否因为 Django 的处理方式而收到此错误?如果是这样,Django 在做什么?或者,我告诉 Django 这样做是为了什么?

编辑1: 我也尝试在这个状态值上使用 Django 的django.utils.encoding。我从saltycrane 中读到了一些关于 Djano 可能会遇到 unicode/utf-8 的问题。

我尝试修改我的日志记录以使用smart_str 功能。

def createXML(self, dict):
    """
    ..  method:: createXML()

        Create a single-depth XML string based on a set of tuples

        :param dict: Set of tuples (simple dictionary)
    """

    xml_string = ''
    for key in dict:
        if (isinstance(dict[key], basestring)):
            if (key == 'v1:State'):
                var_str = smart_str(dict[key])
                for index in range(0, len(var_str)):
                    var = bin(ord(var_str[index]))
                    self.logfile.write(var)
                    self.logfile.write('\n')
                self.logfile.write('{0}\n'.format(var_str))

        xml_string += '<{0}>{1}</{0}>'.format(key, dict[key])

    return xml_string

这样做我可以将正确的值写入日志,但我缩小了 Python 中 .format() 字符串功能的另一个可能问题。当然,我对 python format unicode 的 Google 搜索得到的第一个结果是 Issue 7300,这表明这是 Python 2.7 的一个已知“问题”。

现在,我从another stackoverflow post 找到了一个“解决方案”,它在具有smart_str 功能的 Django 中不起作用(或者至少我无法让它们一起工作)。

我将继续四处挖掘,看看是否找不到根本问题 - 或者至少找不到解决方法。

编辑2: 我通过简单地连接字符串而不是使用.format() 功能找到了一种解决方法。我不喜欢这种“解决方案”——它很丑,但它完成了工作。

def createXML(self, dict):
    """
    ..  method:: createXML()

        Create a single-depth XML string based on a set of tuples

        :param dict: Set of tuples (simple dictionary)
    """

    xml_string = ''
    for key in dict:
        xml_string += '<{0}>'.format(key)
        if (isinstance(dict[key], basestring)):
            xml_string += smart_str(dict[key])
        else:
            xml_string += str(dict[key])
        xml_string += '<{0}>'.format(key)

    return xml_string

我将不回答这个问题,因为我很想找到一个解决方案,让我可以按照预期的方式使用.format()

【问题讨论】:

    标签: django unicode utf-8 python-2.7


    【解决方案1】:

    这是正确的方法(问题在于打开文件。使用 UTF-8 您必须使用 codecs.open()

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import codecs
    
    
    class Writer(object):
        logfile = codecs.open("test.log", "w", 'utf-8')
    
        def createXML(self, dict):
            xml_string = ''
            for key, value in dict.iteritems():
                self.logfile.write(u'\nkey = {0}\n'.format(key))
                if (isinstance(value, basestring)):
                    self.logfile.write(u'basestring\n')
                    self.logfile.write(u'value = {0}\n\n'.format( value))
                else:
                    self.logfile.write(u'value = {0}\n\n'.format( value ))
    
                xml_string += u'<{0}>{1}</{0}>'.format(key, value )
    
            return xml_string
    

    这是来自 python 控制台:

    In [1]: from test import Writer
    
    In [2]: d = { 'a' : u'Zażółć gęślą jaźń', 'b' : u'Och ja Ci zażółcę' }
    
    In [3]: w = Writer()
    
    In [4]: w.createXML(d)
    Out[4]: u'<a>Za\u017c\xf3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144</a><b>Och ja Ci za\u017c\xf3\u0142c\u0119</b>'
    

    这是test.log文件:

    key = a
    basestring
    value = Zażółć gęślą jaźń
    
    
    key = b
    basestring
    value = Och ja Ci zażółcę
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      相关资源
      最近更新 更多