#django #pickle
#django #pickle
Вопрос:
У меня есть простая модель Django с двоичным полем, которую я хотел бы обработать.
class MyModel(models.Model):
bin_data = models.BinaryField()
Исходя из контекста моих unittests, я делаю следующее:
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)
Однако исправление.сбой dumps() с:
TypeError: can't pickle buffer objects
Когда я использую следующую команду для обработки:
data = pickle.dumps(obj, protocol=-1)
Дамп выполняется успешно, но выполняется обработка.loads() завершается с ошибкой:
TypeError: buffer() takes at least 1 argument (0 given)
На самом деле это связано с проблемой, с которой я сталкиваюсь с библиотекой django-cacheops, которую я использую для кэширования моего набора запросов.
В основе django-cacheops лежит использование pickle.выполняется сброс (obj, protocol = -1), и я получаю ту же ошибку, что и описанная выше для pickle.загружает()
Я был бы признателен за ответ как на проблему с pickle, так и на проблему django-cacheops.
Спасибо
Ответ №1:
Мне удалось разгадать тайну, поэтому я мог бы также помочь любому другому, кто мог бы столкнуться с этим.
Эта проблема, по-видимому, связана с ошибкой в модуле pickle в python 2.7, которая не будет исправлена … http://bugs.python.org/issue8323
В двух словах, библиотека pickle (при использовании последнего протокола) способна обрабатывать типы буферов, но не удалять их.
При использовании BinaryField в модели django тип поля в экземпляре модели при загрузке из базы данных — ‘buffer’, что вызывает проблему.
Простым обходным решением было бы преобразовать поле ‘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. Была такая же проблема в Python 3.4.1, django-cache-machine 0.9.1 и Django 1.85. Это исправлено! Я не использую cacheops.
Ответ №2:
Исправлено в cacheops 2.1.1.
Используя внешнюю функцию обработки для буфера таким образом:
import copy_reg
copy_reg.pickle(buffer, lambda b: (buffer, (bytes(b),)))
Комментарии:
1. Еще лучше. Исправление в библиотеке cacheops! Спасибо за это 🙂