# --------------------------------------- fields.py --------------------------------------- # from django.db import models try: import cPickle as pickle except ImportError: import pickle class PickledObject(str): """A subclass of string so it can be told whether a string is a pickled object or not (if the object is an instance of this class then it must [well, should] be a pickled one).""" pass class PickledObjectField(models.Field): __metaclass__ = models.SubfieldBase def to_python(self, value): if isinstance(value, PickledObject): # If the value is a definite pickle; and an error is raised in de-pickling # it should be allowed to propogate. return pickle.loads(str(value)) else: try: return pickle.loads(str(value)) except: # If an error was raised, just return the plain value return value def get_db_prep_save(self, value): if value is not None and not isinstance(value, PickledObject): value = PickledObject(pickle.dumps(value)) return value def get_internal_type(self): return 'TextField' def get_db_prep_lookup(self, lookup_type, value): if lookup_type == 'exact': value = self.get_db_prep_save(value) return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value) elif lookup_type == 'in': value = [self.get_db_prep_save(v) for v in value] return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value) else: raise TypeError('Lookup type %s is not supported.' % lookup_type) # --------------------------------------- tests.py --------------------------------------- # # -*- coding: utf-8 -*- """Unit testing for this module.""" from django.test import TestCase from django.db import models from fields import PickledObjectField class TestingModel(models.Model): pickle_field = PickledObjectField() class TestCustomDataType(str): pass class PickledObjectFieldTests(TestCase): def setUp(self): self.testing_data = ( {1:1, 2:4, 3:6, 4:8, 5:10}, 'Hello World', (1, 2, 3, 4, 5), [1, 2, 3, 4, 5], TestCustomDataType('Hello World'), ) return super(PickledObjectFieldTests, self).setUp() def testDataIntegriry(self): """Tests that data remains the same when saved to and fetched from the database.""" for value in self.testing_data: model_test = TestingModel(pickle_field=value) model_test.save() model_test = TestingModel.objects.get(id__exact=model_test.id) self.assertEquals(value, model_test.pickle_field) model_test.delete() def testLookups(self): """Tests that lookups can be performed on data once stored in the database.""" for value in self.testing_data: model_test = TestingModel(pickle_field=value) model_test.save() self.assertEquals(value, TestingModel.objects.get(pickle_field__exact=value).pickle_field) model_test.delete()