Reputation: 67
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())
print(rv)
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
Upvotes: 3
Views: 2622
Reputation: 456
You can extend Property classes to handle special cases. It is applicable for any property type.
from google.appengine.ext import ndb
class DateTimeProperty(ndb.DateTimeProperty):
# Override to allow JSON serialization
def _get_for_dict(self, entity):
value = super(DateTimeProperty, self)._get_for_dict(entity);
return value.isoformat()
Then use it in your model:
class Users(ndb.Model):
username = ndb.StringProperty(indexed=True)
password= ndb.StringProperty(indexed=True)
created_at = DateTimeProperty(auto_now_add=True)
And to_dict()
as you would normally do:
user = Users.query(Users.username==username).get()
user.to_dict()
Upvotes: 10
Reputation: 8854
Another possible solution - inspired from this answer - is to override to_dict()
in your User
class:
class User(ndb.Model):
username = ndb.StringProperty(indexed=True)
password = ndb.StringProperty(indexed=False)
created_at = DateTimeProperty(auto_now_add=True)
def to_dict(self):
result = super(User, self).to_dict()
result['created_at'] = self.created_at.isoformat()
return result
Upvotes: 1
Reputation: 2536
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': o.lat, 'lon': o.lon}
if isinstance(o, ndb.Key):
return o.urlsafe()
if isinstance(o, ndb.Model):
dct = o.to_dict()
dct['id'] = o.key.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']))
Upvotes: 6