fields.py 2.2 KB

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