hstore_field.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. from typing import List, Optional, Tuple, Union
  2. from django.contrib.postgres.fields import HStoreField as DjangoHStoreField
  3. from django.db.models.expressions import Expression
  4. from django.db.models.fields import Field
  5. class HStoreField(DjangoHStoreField):
  6. """Improved version of Django's :see:HStoreField that adds support for
  7. database-level constraints.
  8. Notes:
  9. - For the implementation of uniqueness, see the
  10. custom database back-end.
  11. """
  12. def __init__(
  13. self,
  14. *args,
  15. uniqueness: Optional[List[Union[str, Tuple[str, ...]]]] = None,
  16. required: Optional[List[str]] = None,
  17. **kwargs
  18. ):
  19. """Initializes a new instance of :see:HStoreField.
  20. Arguments:
  21. uniqueness:
  22. List of keys to enforce as unique. Use tuples
  23. to enforce multiple keys together to be unique.
  24. required:
  25. List of keys that should be enforced as required.
  26. """
  27. super(HStoreField, self).__init__(*args, **kwargs)
  28. self.uniqueness = uniqueness
  29. self.required = required
  30. def get_prep_value(self, value):
  31. """Override the base class so it doesn't cast all values to strings.
  32. psqlextra supports expressions in hstore fields, so casting all
  33. values to strings is a bad idea.
  34. """
  35. value = Field.get_prep_value(self, value)
  36. if isinstance(value, dict):
  37. prep_value = {}
  38. for key, val in value.items():
  39. if isinstance(val, Expression):
  40. prep_value[key] = val
  41. elif val is not None:
  42. prep_value[key] = str(val)
  43. else:
  44. prep_value[key] = val
  45. value = prep_value
  46. if isinstance(value, list):
  47. value = [str(item) for item in value]
  48. return value
  49. def deconstruct(self):
  50. """Gets the values to pass to :see:__init__ when re-creating this
  51. object."""
  52. name, path, args, kwargs = super(HStoreField, self).deconstruct()
  53. if self.uniqueness is not None:
  54. kwargs["uniqueness"] = self.uniqueness
  55. if self.required is not None:
  56. kwargs["required"] = self.required
  57. return name, path, args, kwargs