在缓存中用二进制字段腌制django模型

时间:2014-07-07 11:49:37

标签: django pickle

我有一个简单的Django模型,带有二元字段,我想腌制。

class MyModel(models.Model):
    bin_data = models.BinaryField()

从我的单元测试的上下文中,我执行以下操作:

import pickle
tmp_obj = MyModel.objects.create(bin_data="12345")
obj = MyModel.objects.get(pk=tmp_obj.pk)  # load from DB
data = pickle.dumps(obj)
obj2 = pickle.loads(data)

然而,pickle.dumps()失败了:

TypeError: can't pickle buffer objects

当我使用以下命令进行pickle时:

data = pickle.dumps(obj, protocol=-1)

转储成功,但pickle.loads()失败并显示:

TypeError: buffer() takes at least 1 argument (0 given)

这实际上与我正在使用的django-cacheops库中存在的问题有关,以便缓存我的查询集。

引擎盖django-cacheops使用pickle.dumps(obj,protocol = -1),我收到与上述pickle.loads()

相同的错误

我很感激pickle问题和django-cacheops问题的答案。

由于

2 个答案:

答案 0 :(得分:3)

我设法解开了这个谜团,所以我不妨帮助其他可能遇到它的人。

这个问题显然与python 2.7中的pickle模块中的一个错误有关,不会修复... http://bugs.python.org/issue8323

简而言之,pickle库(使用最新协议时)能够腌制缓冲区类型,但不能解开它们。

在django模型中使用BinaryField时,从DB加载时模型实例中的字段类型是“缓冲区”,这会导致问题。

一个简单的解决方法是将'buffer'字段转换为'str'。

至于我的例子,这可以使用post_init信号轻松完成:

class MyModel(models.Model):
    bin_data = models.BinaryField()


from django.db.models.signals import post_init

def on_model_load(sender, **kwargs):
    model_obj = kwargs.get('instance', None)
    if model_obj and model_obj.bin_data is not None:
        model_obj.bin_data = str(model_obj.bin_data)

post_init.connect(on_model_load, sender=MyModel)

解决方法将允许修改模型实例并修复django-cacheops模块的行为。

答案 1 :(得分:2)

已修复cacheops 2.1.1

以这种方式使用外部酸洗功能缓冲:

import copy_reg
copy_reg.pickle(buffer, lambda b: (buffer, (bytes(b),)))