Skip to content

Instantly share code, notes, and snippets.

@sontek
Forked from goodwillcoding/gist:3808931
Created October 1, 2012 01:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sontek/3809010 to your computer and use it in GitHub Desktop.
Save sontek/3809010 to your computer and use it in GitHub Desktop.
JSON Serializable SQLAlchemy Object
class JsonSerializableMixin(object):
"""
Converts all the properties of the object into a dict for use in json.
You can define the following as your class properties.
_json_eager_load :
list of which child classes need to be eagerly loaded. This applies
to one-to-many relationships defined in SQLAlchemy classes.
_base_blacklist :
top level blacklist list of which properties not to include in JSON
_json_blacklist :
blacklist list of which properties not to include in JSON
"""
def __json__(self, request):
"""
Main JSONify method
:param request: Pyramid Request object
:type request: <Request>
:return: dictionary ready to be jsonified
:rtype: <dict>
"""
props = {}
# grab the json_eager_load set, if it exists
# use set for easy 'in' lookups
json_eager_load = set(getattr(self, '_json_eager_load', []))
# now load the property if it exists
# (does this issue too many SQL statements?)
for prop in json_eager_load:
getattr(self, prop, None)
# we make a copy because the dict will change if the database
# is updated / flushed
options = self.__dict__.copy()
# setup the blacklist
# use set for easy 'in' lookups
blacklist = set(getattr(self, '_base_blacklist', []))
# extend the base blacklist with the json blacklist
blacklist.update(getattr(self, '_json_blacklist', []))
for key in options:
# skip blacklisted properties
if key in blacklist:
continue
# do not include private and SQLAlchemy properties
if key.startswith(('__', '_sa_')):
continue
# format and date/datetime/time properties to isoformat
obj = getattr(self, key)
if isinstance(obj, (datetime, date, time)):
props[key] = obj.isoformat()
continue
# get the class property value
attr = getattr(self, key)
# let see if we need to eagerly load it
# this is for SQLAlchemy foreign key fields that
# indicate with one-to-many relationships
if key in json_eager_load and attr:
if hasattr(attr, '_sa_instance_state'):
props[key] = self.__try_to_json(request, attr)
else:
# jsonify all child objects
props[key] = [self.__try_to_json(request, x) for x in attr]
continue
# convert all non integer strings to string or if string conversion
# is not possible, convert it to Unicode
if attr and not isinstance(attr, (int, float)):
try:
props[key] = str(attr)
except UnicodeEncodeError:
props[key] = unicode(attr) # .encode('utf-8')
continue
props[key] = attr
return props
def __try_to_json(self, request, attr):
"""
Try to run __json__ on the given object.
Raise TypeError is __json__ is missing
:param request: Pyramid Request object
:type request: <Request>
:param obj: Object to JSONify
:type obj: any object that has __json__ method
:exception: TypeError
"""
# check for __json__ method and try to JSONify
if hasattr(attr, '__json__'):
return attr.__json__(request)
# raise error otherwise
raise TypeError('__json__ method missing on %s' % str(attr))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment