Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added jsonfield

  • Loading branch information...
commit 775f4393d43bf238295414c8ef9d5bd1db8caf86 1 parent 8109ebf
quantmind authored
View
5 CHANGELOG.rst
@@ -1,3 +1,8 @@
+Ver. 0.4.3
+======================
+* Added :class:`stdnet.orm.JSONField` with tests.
+* **58 tests**.
+
Ver. 0.4.2 - 2010 Nov 17
============================
* Added ``tags`` in tests. You can now run specific tags::
View
25 stdnet/orm/fields.py
@@ -7,6 +7,7 @@
from related import RelatedObject, ReverseSingleRelatedObjectDescriptor
from stdnet.exceptions import *
from stdnet.utils import timestamp2date, date2timestamp
+from stdnet.utils import json, json_compact, DefaultJSONEncoder, DefaultJSONHook
try:
import cPickle as pickle
@@ -27,6 +28,7 @@
'SymbolField',
'CharField',
'ForeignKey',
+ 'JSONField',
'PickleObjectField',
'_novalue']
@@ -367,4 +369,27 @@ def serialize(self, value):
return value.id
except:
return value
+
+
+class JSONField(CharField):
+ type = 'json object'
+ def __init__(self, *args, **kwargs):
+ kwargs['default'] = kwargs.get('default','{}')
+ self.encoder_class = kwargs.pop('encoder_class',DefaultJSONEncoder)
+ self.decoder_hook = kwargs.pop('decoder_hook',DefaultJSONHook)
+ self.sep = kwargs.pop('sep',None)
+ super(JSONField,self).__init__(*args, **kwargs)
+
+ def to_python(self, value):
+ if isinstance(value, basestring):
+ if not value:
+ value = {}
+ else:
+ value = json.loads(value, object_hook = self.decoder_hook)
+ return value
+
+ def serialize(self, value):
+ if value is not None:
+ value = json.dumps(json_compact(value,self.sep), cls=self.encoder_class)
+ return value
View
80 stdnet/tests/atomfields.py
@@ -1,21 +1,19 @@
-import datetime
-import unittest
-import logging
+from datetime import date, datetime
+from decimal import Decimal
from itertools import izip
import stdnet
-from stdnet.test import TestCase
+from stdnet import test
from stdnet.utils import populate
-from examples.models import TestDateModel
+from examples.models import TestDateModel, Statistics, Statistics2
NUM_DATES = 100
names = populate('string',NUM_DATES, min_len = 5, max_len = 20)
-dates = populate('date', NUM_DATES, start=datetime.date(2010,5,1), end=datetime.date(2010,6,1))
+dates = populate('date', NUM_DATES, start=date(2010,5,1), end=date(2010,6,1))
-
-class TestAtomFields(TestCase):
+class TestAtomFields(test.TestCase):
def setUp(self):
self.orm.register(TestDateModel)
@@ -64,7 +62,71 @@ def testDelete(self):
self.assertEqual(keys[0],self.meta.autoid())
-class TestErrorAtomFields(TestCase):
+class TestJsonField(test.TestCase):
+ tags = ['json']
+
+ def setUp(self):
+ self.orm.register(Statistics)
+
+ def unregister(self):
+ self.orm.unregister(Statistics)
+
+ def testMetaData(self):
+ field = Statistics._meta.dfields['data']
+ self.assertEqual(field.sep,None)
+
+ def testCreate(self):
+ mean = Decimal('56.4')
+ started = date(2010,1,1)
+ timestamp = datetime.now()
+ a = Statistics(dt = date.today(), data = {'mean': mean,
+ 'std': 5.78,
+ 'started': started,
+ 'timestamp':timestamp}).save()
+ self.assertEqual(a.data['mean'],mean)
+ a = Statistics.objects.get(id = a.id)
+ self.assertEqual(len(a.data),4)
+ self.assertEqual(a.data['mean'],mean)
+ self.assertEqual(a.data['started'],started)
+ self.assertEqual(a.data['timestamp'],timestamp)
+
+
+class TestJsonFieldSep(test.TestCase):
+ tags = ['json']
+
+ def setUp(self):
+ self.orm.register(Statistics2)
+
+ def unregister(self):
+ self.orm.unregister(Statistics2)
+
+ def testMetaData(self):
+ field = Statistics2._meta.dfields['data']
+ self.assertEqual(field.sep,'__')
+
+ def testCreate(self):
+ mean = Decimal('56.4')
+ started = date(2010,1,1)
+ timestamp = datetime.now()
+ a = Statistics2(dt = date.today(), data = {'stat__mean': mean,
+ 'stat__std': 5.78,
+ 'stat__secondary__ar': 0.1,
+ 'date__started': started,
+ 'date__timestamp':timestamp}).save()
+ a = Statistics2.objects.get(id = a.id)
+ self.assertEqual(len(a.data),2)
+ stat = a.data['stat']
+ dt = a.data['date']
+ self.assertEqual(len(stat),3)
+ self.assertEqual(len(dt),2)
+
+ self.assertEqual(stat['mean'],mean)
+ self.assertEqual(stat['secondary']['ar'],0.1)
+ self.assertEqual(dt['started'],started)
+ self.assertEqual(dt['timestamp'],timestamp)
+
+
+class TestErrorAtomFields(test.TestCase):
def testNotRegistered(self):
m = TestDateModel(name = names[1], dt = dates[0])
View
14 stdnet/tests/examples/models.py
@@ -18,6 +18,8 @@ class SimpleModel(orm.StdModel):
objects = CustomManager()
+
+
#####################################################################
# FINANCE APPLICATION
@@ -139,3 +141,15 @@ def newupdate(self, data):
self.updates.push_front(p)
return p
+
+##############################################
+# JSON FIELD
+
+class Statistics(orm.StdModel):
+ dt = orm.DateField()
+ data = orm.JSONField()
+
+class Statistics2(orm.StdModel):
+ dt = orm.DateField()
+ data = orm.JSONField(sep = '__')
+
View
2  stdnet/utils/__init__.py
@@ -4,7 +4,7 @@
from encoding import *
from rwlock import *
from importlib import *
-from anyjson import *
+from jsontools import *
from odict import *
from populate import populate
from fields import *
View
27 stdnet/utils/anyjson.py
@@ -1,27 +0,0 @@
-import time
-from datetime import date, datetime
-try:
- import json
-except:
- import simplejson as json
-
-date2timestamp = lambda dte : int(time.mktime(dte.timetuple()))
-
-class JSONRPCEncoder(json.JSONEncoder):
- """
- Provide custom serializers for JSON-RPC.
- """
- def default(self, obj):
- if isinstance(obj, date) or isinstance(obj, datetime):
- return date2timestamp(obj)
- else:
- raise exceptions.JSONEncodeException("%r is not JSON serializable" % (obj,))
-
-
-class jsonPickler(object):
-
- def dumps(self, obj, **kwargs):
- return json.dumps(res, cls=JSONRPCEncoder, **kwargs)
-
- def loads(self,sobj):
- return json.loads(sobj)
View
82 stdnet/utils/jsontools.py
@@ -0,0 +1,82 @@
+import time
+from datetime import date, datetime
+from decimal import Decimal
+import json
+
+date2timestamp = lambda dte : int(time.mktime(dte.timetuple()))
+
+
+def totimestamp(dte):
+ return time.mktime(dte.timetuple())
+
+def totimestamp2(dte):
+ return totimestamp(dte) + 0.000001*dte.microsecond
+
+def todatetime(tstamp):
+ return datetime.fromtimestamp(tstamp)
+
+
+def json_compact(data, sep = '_'):
+ if not sep:
+ return data
+ d = {}
+ for k,v in data.items():
+ rdata = d
+ keys = k.split(sep)
+ for key in keys[:-1]:
+ kd = rdata.get(key,None)
+ if kd is None:
+ kd = {}
+ rdata[key] = kd
+ rdata = kd
+ rdata[keys[-1]] = v
+ return d
+
+
+class JSONDateDecimalEncoder(json.JSONEncoder):
+ """
+ Provide custom serializers for JSON-RPC.
+ """
+ def default(self, obj):
+ if isinstance(obj,datetime):
+ return {'__datetime__':totimestamp2(obj)}
+ elif isinstance(obj, date):
+ return {'__date__':totimestamp(obj)}
+ elif isinstance(obj, Decimal):
+ return {'__decimal__':str(obj)}
+ else:
+ raise ValueError("%r is not JSON serializable" % (obj,))
+
+
+def date_decimal_hook(dct):
+ if '__datetime__' in dct:
+ return todatetime(dct['__datetime__'])
+ elif '__date__' in dct:
+ return todatetime(dct['__date__']).date()
+ elif '__decimal__' in dct:
+ return Decimal(dct['__decimal__'])
+ else:
+ return dct
+
+
+DefaultJSONEncoder = JSONDateDecimalEncoder
+DefaultJSONHook = date_decimal_hook
+
+class JSONRPCEncoder(json.JSONEncoder):
+ """
+ Provide custom serializers for JSON-RPC.
+ """
+ def default(self, obj):
+ if isinstance(obj, date) or isinstance(obj, datetime):
+ return date2timestamp(obj)
+ else:
+ raise exceptions.JSONEncodeException("%r is not JSON serializable" % (obj,))
+
+
+class jsonPickler(object):
+
+ def dumps(self, obj, **kwargs):
+ return json.dumps(res, cls=JSONRPCEncoder, **kwargs)
+
+ def loads(self,sobj):
+ return json.loads(sobj)
Please sign in to comment.
Something went wrong with that request. Please try again.