json.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. # -*- coding: utf-8 -*-
  2. """
  3. JSONField automatically serializes most Python terms to JSON data.
  4. Creates a TEXT field with a default value of "{}". See test_json.py for
  5. more information.
  6. from django.db import models
  7. from django_extensions.db.fields import json
  8. class LOL(models.Model):
  9. extra = json.JSONField()
  10. """
  11. from __future__ import absolute_import
  12. import json
  13. import six
  14. import django
  15. from django.core.serializers.json import DjangoJSONEncoder
  16. from django.db import models
  17. def dumps(value):
  18. return DjangoJSONEncoder().encode(value)
  19. def loads(txt):
  20. return json.loads(txt)
  21. class JSONDict(dict):
  22. """
  23. Hack so repr() called by dumpdata will output JSON instead of
  24. Python formatted data. This way fixtures will work!
  25. """
  26. def __repr__(self):
  27. return dumps(self)
  28. class JSONList(list):
  29. """
  30. Hack so repr() called by dumpdata will output JSON instead of
  31. Python formatted data. This way fixtures will work!
  32. """
  33. def __repr__(self):
  34. return dumps(self)
  35. class JSONField(models.TextField):
  36. """
  37. JSONField is a generic textfield that neatly serializes/unserializes
  38. JSON objects seamlessly. Main thingy must be a dict object.
  39. """
  40. def __init__(self, *args, **kwargs):
  41. kwargs['default'] = kwargs.get('default', dict)
  42. models.TextField.__init__(self, *args, **kwargs)
  43. def get_default(self):
  44. if self.has_default():
  45. default = self.default
  46. if callable(default):
  47. default = default()
  48. return self.to_python(default)
  49. return super().get_default()
  50. def to_python(self, value):
  51. """Convert our string value to JSON after we load it from the DB"""
  52. if value is None or value == '':
  53. return {}
  54. if isinstance(value, six.string_types):
  55. res = loads(value)
  56. else:
  57. res = value
  58. if isinstance(res, dict):
  59. return JSONDict(**res)
  60. elif isinstance(res, list):
  61. return JSONList(res)
  62. return res
  63. def get_prep_value(self, value):
  64. if not isinstance(value, six.string_types):
  65. return dumps(value)
  66. return super(models.TextField, self).get_prep_value(value)
  67. if django.VERSION < (2, ):
  68. def from_db_value(self, value, expression, connection, context):
  69. return self.to_python(value)
  70. else:
  71. def from_db_value(self, value, expression, connection): # type: ignore
  72. return self.to_python(value)
  73. def get_db_prep_save(self, value, connection, **kwargs):
  74. """Convert our JSON object to a string before we save"""
  75. if value is None and self.null:
  76. return None
  77. # default values come in as strings; only non-strings should be
  78. # run through `dumps`
  79. if not isinstance(value, six.string_types):
  80. value = dumps(value)
  81. return value
  82. def deconstruct(self):
  83. name, path, args, kwargs = super().deconstruct()
  84. if self.default == '{}':
  85. del kwargs['default']
  86. return name, path, args, kwargs