fields.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. """
  2. Custom Django Model Fields.
  3. """
  4. from django.db import models
  5. from django.conf import settings
  6. from celery.serialization import pickle
  7. class PickledObject(str):
  8. """A subclass of string so it can be told whether a string is
  9. a pickled object or not (if the object is an instance of this class
  10. then it must [well, should] be a pickled one)."""
  11. pass
  12. if settings.DATABASE_ENGINE == "postgresql_psycopg2":
  13. import psycopg2.extensions
  14. # register PickledObject as a QuotedString otherwise we will see
  15. # can't adapt errors from psycopg2.
  16. psycopg2.extensions.register_adapter(PickledObject,
  17. psycopg2.extensions.QuotedString)
  18. class PickledObjectField(models.Field):
  19. """A field that automatically pickles/unpickles its value."""
  20. __metaclass__ = models.SubfieldBase
  21. def to_python(self, value):
  22. """Convert the database value to a python value."""
  23. if isinstance(value, PickledObject):
  24. # If the value is a definite pickle; and an error is
  25. # raised in de-pickling it should be allowed to propogate.
  26. return pickle.loads(str(value))
  27. else:
  28. try:
  29. return pickle.loads(str(value))
  30. except Exception:
  31. # If an error was raised, just return the plain value
  32. return value
  33. def get_db_prep_save(self, value):
  34. """get_db_prep_save"""
  35. if value is not None and not isinstance(value, PickledObject):
  36. value = PickledObject(pickle.dumps(value))
  37. return value
  38. def get_internal_type(self):
  39. """The database field type used by this field."""
  40. return 'TextField'
  41. def get_db_prep_lookup(self, lookup_type, value):
  42. """get_db_prep_lookup"""
  43. if lookup_type == 'exact':
  44. value = self.get_db_prep_save(value)
  45. return super(PickledObjectField, self).get_db_prep_lookup(
  46. lookup_type, value)
  47. elif lookup_type == 'in':
  48. value = [self.get_db_prep_save(v) for v in value]
  49. return super(PickledObjectField, self).get_db_prep_lookup(
  50. lookup_type, value)
  51. else:
  52. raise TypeError('Lookup type %s is not supported.' % lookup_type)