应用程序引擎数据存储to_dict将ndb.Model序列化为JSON的替代方法

时间:2014-09-16 14:21:59

标签: json python-2.7 google-app-engine google-cloud-datastore app-engine-ndb

我有一个我想要转换为JSON的ndb.Model。

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)

它抛出了这个错误:

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

这里的大多数解决方案都是针对db.Model的,并且已经过时了。

sdk version 1.9.10

3 个答案:

答案 0 :(得分:10)

您可以扩展Property类来处理特殊情况。它适用于任何属性类型。

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()

然后在您的模型中使用它:

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

to_dict()一样:

user = Users.query(Users.username==username).get()
user.to_dict()

答案 1 :(得分:5)

您需要一个自定义的“to JSON”转换器来处理JSON本身不支持的格式。

我正在使用以下代码来处理大多数情况。

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

所以在我的情况下,我也在处理其他一些事情,比如GeoPt,并为所有ndb.Model添加一个ID字段,但对于你的情况,你需要的只是:

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

但我猜(不确定)你会得到一个关键错误,所以你也需要

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

如果您不需要 created_at 字段,则可以将其排除在外,如

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

答案 2 :(得分:0)

另一个可能的解决方案 - 受this回答启发 - 是覆盖to_dict()课程中的User

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