Jor*_*tao 10 python django unicode utf-8 pickle
我有一个数据库(mysql),我想存储pickle数据.
数据可以是例如字典,其可以包含例如unicode
data = {1 : u'é'}
Run Code Online (Sandbox Code Playgroud)
数据库(mysql)在utf-8中.
当我泡菜时,
import pickle
pickled_data = pickle.dumps(data)
print type(pickled_data) # returns <type 'str'>
Run Code Online (Sandbox Code Playgroud)
结果pickled_data是一个字符串.
当我尝试将其存储在数据库中时(例如在文本字段中),这可能会导致问题.特别是,我在某个方面得到了一个
UnicodeDecodeError "'utf8' codec can't decode byte 0xe9 in position X"
Run Code Online (Sandbox Code Playgroud)
当试图在数据库中保存pickled_data时.这是有道理的,因为pickled_data可以有非utf-8字符.我的问题是如何在utf-8数据库上存储pickled_data?
我看到两个可能的候选人:
将pickle.dump的结果编码为utf-8并存储它.当我想pickle.load时,我必须解码它.
以二进制格式存储pickle字符串(如何?),这会强制所有字符都在ascii中.
我的问题是,从长远来看,我没有看到选择其中一个选项会产生什么后果.由于这一变化需要付出一些努力,因此我想要就此问题征求意见,要求最终更好的候选人.
(PS这在Django中很有用)
Mar*_*ers 15
即使您使用协议版本0,Pickle数据也是不透明的二进制数据:
>>> pickle.dumps(data, 0)
'(dp0\nI1\nV\xe9\np1\ns.'
Run Code Online (Sandbox Code Playgroud)
当您尝试将其存储在a中时TextField
,Django将尝试将该数据解码为UTF8以存储它; 这是失败的原因,因为这不是UTF-8编码数据; 它是二进制数据:
>>> pickled_data.decode('utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/encodings/utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xe9 in position 9: invalid continuation byte
Run Code Online (Sandbox Code Playgroud)
解决方案是不要试图将其存储在一个TextField
.用一个BinaryField
代替:
用于存储原始二进制数据的字段.它只支持
bytes
分配.请注意,此字段的功能有限.例如,无法在BinaryField值上过滤查询集.
你有一个bytes
值(Python 2字符串是字节字符串,bytes
在Python 3中重命名).
如果您坚持将数据存储在文本字段中,请将其明确解码为latin1
; Latin 1编解码器将字节一对一映射到Unicode代码点:
>>> pickled_data.decode('latin1')
u'(dp0\nI1\nV\xe9\np1\ns.'
Run Code Online (Sandbox Code Playgroud)
并确保在再次打开之前再次对其进行编码:
>>> encoded = pickled_data.decode('latin1')
>>> pickle.loads(encoded)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/mj/Development/Libraries/buildout.python/parts/opt/lib/python2.7/pickle.py", line 1381, in loads
file = StringIO(str)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 9: ordinal not in range(128)
>>> pickle.loads(encoded.encode('latin1'))
{1: u'\xe9'}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您将此值转到浏览器并再次返回文本字段,则浏览器可能已替换该数据中的字符.例如,Internet Explorer将替换\n
字符\r\n
,因为它假定它处理文本.
并不是说你曾经允许在任何情况下接受来自网络连接的pickle数据,因为这是一个等待利用的安全漏洞.
归档时间: |
|
查看次数: |
19012 次 |
最近记录: |