Skip to content

Instantly share code, notes, and snippets.

@pjenvey
Created October 1, 2012 00:38
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save pjenvey/3808830 to your computer and use it in GitHub Desktop.
Save pjenvey/3808830 to your computer and use it in GitHub Desktop.
JSON Serializable SQLAlchemy Object
class JsonSerializableMixin(object):
def __json__(self, request):
"""
Converts all the properties of the object into a dict for use in json.
You can define the following in your class
_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
: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, private and SQLAlchemy properties
if key in blacklist or 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()
else:
# get the class property value
attr = getattr(self, key)
# let see if we need to eagerly load it
if key in json_eager_load:
# this is for SQLAlchemy foreign key fields that
# indicate with one-to-many relationships
if not hasattr(attr, 'pk') and attr:
# jsonify all child objects
attr = [x.__json__(request) for x in attr]
else:
# 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:
attr = str(attr)
except UnicodeEncodeError:
attr = unicode(attr) # .encode('utf-8')
props[key] = attr
return props
@mattdeboard
Copy link

Sweet, definitely ripping this off minus the request object as I'm not using Pyramid. Appreciate it, especially because it's so well-commented and just generally great-looking code. Thanks!

@kmarekspartz
Copy link

I see other people are "ripping this off". How is this licensed? I'd like to use it, too, plus I have an idea on a @class_method from_json.

@kmarekspartz
Copy link

It was easier to extend JSONEncoder from the standard library.

@jackton1
Copy link

The cost of this loop is very expensive with the conditionals here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment