Jeffrey V Jeffrey V - 4 months ago 46
JSON Question

App engine datastore to_dict alternative to serialize ndb.Model to JSON

I have a ndb.Model that I want to convert to JSON.

class Users(ndb.Model):
username = ndb.StringProperty(indexed=True)
password= ndb.StringProperty(indexed=True)
created_at = ndb.DateTimeProperty(auto_now_add=True)

user = Users.query(Users.username==username).get()
rv = json.dumps(user.to_dict())

It throws this error:

TypeError: datetime.datetime(2013, 11, 24, 3, 40, 15) is not JSON serializable

Most of the solutions here are for db.Model and are fairly outdated.

sdk version 1.9.10


You would need a custom "to JSON" converter that handles formats not natively supported by JSON.

I am using something like the following code that handles most situations for me.

def to_json(self, o):
    if isinstance(o, list):
        return [self.to_json(l) for l in o]
    if isinstance(o, dict):
        x = {}
        for l in o:
            x[l] = self.to_json(o[l])
        return x
    if isinstance(o, datetime.datetime):
        return o.isoformat()
    if isinstance(o, ndb.GeoPt):
        return {'lat':, 'lon': o.lon}
    if isinstance(o, ndb.Key):
        return o.urlsafe()
    if isinstance(o, ndb.Model):
        dct = o.to_dict()
        dct['id'] =
        return self.to_json(dct)
    return o

So in my case I am also taking care of some other things like GeoPt, and adding an ID field to all ndb.Models but for your case all you'd need would be:

    if isinstance(o, datetime.datetime):
        return o.isoformat()

but I am guessing (not really sure) you would then get a key error as well so you'd also need

    if isinstance(o, ndb.Key):
        return o.urlsafe()

In case if you didn't need the created_at field, you could simply exclude it like

rv = json.dumps(user.to_dict(exclude=['created_at']))