腌制/解开更复杂的物体

时间:2019-11-12 18:59:30

标签: django persistence pickle python-3.7

我有一个更复杂的对象,它也包含一些继承等。我希望能够对其进行腌制/解开并将其另存为文件。但是它只有在内存中时才起作用。当我将其读取为文件时,无法正确将其转换回去。

只要我在python(Django)应用程序中使用它就可以了:

myPickle=pickle.dumps(reallyComplicatedObject, 0).decode()
...
myObject = pickle.loads(myPickle.encode())

现在我将其保存以备将来使用(我不得不假装它是一个文件,因为Django不允许我将字符串另存为文件):

fs = FileSystemStorage()

notAFile = io.StringIO(pickle.dumps(reallyComplicatedObject, 0).decode())
filename = fs.save(filename, notAFile)
return fs.url(filename)

这与预期的一样。我有一个看起来对我来说或多或少是二进制文件 现在,请注意:

storage_class = get_storage_class(settings.STATICFILES_STORAGE)
complicatedPickle = None

with storage_class().open('TestFiles/Pickles/thatOneObject') as picklereads:
    complicatedPickle = picklereads.read()
pick = pickle.loads(complicatedPickle)

当我输出complicatedPickle时,我得到了一个长字符串,它看起来对我来说是二进制的。在这里,我已经很奇怪了,正如我期望的那样,它是一个字符串-

(Pdb) type(complicatedPickle)
<class 'bytes'>

pick是一个字符串,对其进行编码只会使其再次变为二进制:

(Pdb) type(pick)
<class 'str'>
(Pdb) type(pick.encode())
<class 'bytes'>

我已尝试在此解决方案中使用ast,例如:https://stackoverflow.com/a/52891113/2516892

nopick = pickle.loads(ast.literal_eval(complicatedPickle))

但是出问题了,因为这只是输出对象。之后,我没有nopick变量。

同一页面上的下一个解决方案也没有帮助:

(Pdb) unpick=pickle.loads(bytes(complicatedPickle))
(Pdb) type(unpick)
<class 'str'>
(Pdb) unpick=pickle.loads(bytes(complicatedPickle, "latin1"))
*** TypeError: encoding without a string argument
(Pdb) unpick=pickle.load(bytes(complicatedPickle, "latin1"))
*** TypeError: encoding without a string argument

我现在被困住了。我的转换中已经有错误吗?还是我应该再次使其物化?还是该问题可能与Django有关,因为我没有使用常规的open,而是使用storage_class

1 个答案:

答案 0 :(得分:0)

这里有两个主要问题:

  1. FileSystemStorage不能写二进制文件,StringIO不能假装String是二进制的(也许可以,但是并不是很简单)
  2. 读取非二进制保存的文件并假装它实际上是二进制文件不起作用。

我需要将保存功能抛弃为非Django风格:

import os
    sfilename = os.path.join(settings.STATIC_ROOT,
                             "TestFiles/Pickles/"+filename)

    with open(sfilename, 'wb') as f:
        f.write(pickle.dumps(obj, 0)) #also not decoding it any more

    return sfilename

检索更为简单:

with storage_class().open('TestFiles/Pickles/'+filename, mode='rb') as pickle:
            complicatedObject = pickle.load(pickle)

就是这样