json.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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 datetime
  13. from decimal import Decimal
  14. import json
  15. import six
  16. from django.conf import settings
  17. from mongoengine.fields import StringField
  18. class JSONEncoder(json.JSONEncoder):
  19. def default(self, obj):
  20. if isinstance(obj, Decimal):
  21. return str(obj)
  22. elif isinstance(obj, datetime.datetime):
  23. assert settings.TIME_ZONE == 'UTC'
  24. return obj.strftime('%Y-%m-%dT%H:%M:%SZ')
  25. return json.JSONEncoder.default(self, obj)
  26. def dumps(value):
  27. assert isinstance(value, dict)
  28. return JSONEncoder().encode(value)
  29. def loads(txt):
  30. value = json.loads(txt, parse_float=Decimal)
  31. assert isinstance(value, dict)
  32. return value
  33. class JSONDict(dict):
  34. """
  35. Hack so repr() called by dumpdata will output JSON instead of
  36. Python formatted data. This way fixtures will work!
  37. """
  38. def __repr__(self):
  39. return dumps(self)
  40. class JSONField(StringField):
  41. """
  42. JSONField is a generic textfield that neatly serializes/unserializes
  43. JSON objects seamlessly. Main object must be a dict object.
  44. """
  45. def __init__(self, *args, **kwargs):
  46. if 'default' not in kwargs:
  47. kwargs['default'] = '{}'
  48. StringField.__init__(self, *args, **kwargs)
  49. def to_python(self, value):
  50. """ Convert our string value to JSON after we load it from the DB """
  51. if not value:
  52. return {}
  53. elif isinstance(value, six.string_types):
  54. res = loads(value)
  55. assert isinstance(res, dict)
  56. return JSONDict(**res)
  57. else:
  58. return value
  59. def get_db_prep_save(self, value):
  60. """ Convert our JSON object to a string before we save """
  61. if not value:
  62. return super().get_db_prep_save("")
  63. else:
  64. return super().get_db_prep_save(dumps(value))