File: json.py

package info (click to toggle)
python-django-extensions 4.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,812 kB
  • sloc: python: 18,601; javascript: 7,354; makefile: 108; xml: 17
file content (80 lines) | stat: -rw-r--r-- 2,154 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# -*- coding: utf-8 -*-
"""
JSONField automatically serializes most Python terms to JSON data.
Creates a TEXT field with a default value of "{}".  See test_json.py for
more information.

 from django.db import models
 from django_extensions.db.fields import json

 class LOL(models.Model):
     extra = json.JSONField()
"""

import datetime
from decimal import Decimal

import json
from django.conf import settings
from mongoengine.fields import StringField


class JSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return str(obj)
        elif isinstance(obj, datetime.datetime):
            assert settings.TIME_ZONE == "UTC"
            return obj.strftime("%Y-%m-%dT%H:%M:%SZ")
        return json.JSONEncoder.default(self, obj)


def dumps(value):
    assert isinstance(value, dict)
    return JSONEncoder().encode(value)


def loads(txt):
    value = json.loads(txt, parse_float=Decimal)
    assert isinstance(value, dict)
    return value


class JSONDict(dict):
    """
    Hack so repr() called by dumpdata will output JSON instead of
    Python formatted data.  This way fixtures will work!
    """

    def __repr__(self):
        return dumps(self)


class JSONField(StringField):
    """
    JSONField is a generic textfield that neatly serializes/unserializes
    JSON objects seamlessly. Main object must be a dict object.
    """

    def __init__(self, *args, **kwargs):
        if "default" not in kwargs:
            kwargs["default"] = "{}"
        StringField.__init__(self, *args, **kwargs)

    def to_python(self, value):
        """Convert our string value to JSON after we load it from the DB"""
        if not value:
            return {}
        elif isinstance(value, str):
            res = loads(value)
            assert isinstance(res, dict)
            return JSONDict(**res)
        else:
            return value

    def get_db_prep_save(self, value):
        """Convert our JSON object to a string before we save"""
        if not value:
            return super().get_db_prep_save("")
        else:
            return super().get_db_prep_save(dumps(value))