Google App Engine模型的JSON序列化

use*_*677 86 python google-app-engine json

我一直在寻找一段时间没有成功.我的项目没有使用Django,是否有一种简单的方法将App Engine模型(google.appengine.ext.db.Model)序列化为JSON,还是需要编写自己的序列化程序?

模型:

class Photo(db.Model):
    filename = db.StringProperty()
    title = db.StringProperty()
    description = db.StringProperty(multiline=True)
    date_taken = db.DateTimeProperty()
    date_uploaded = db.DateTimeProperty(auto_now_add=True)
    album = db.ReferenceProperty(Album, collection_name='photo')
Run Code Online (Sandbox Code Playgroud)

dmw*_*dmw 62

一个简单的递归函数可用于将实体(和任何引用)转换为可以传递给的嵌套字典simplejson:

import datetime
import time

SIMPLE_TYPES = (int, long, float, bool, dict, basestring, list)

def to_dict(model):
    output = {}

    for key, prop in model.properties().iteritems():
        value = getattr(model, key)

        if value is None or isinstance(value, SIMPLE_TYPES):
            output[key] = value
        elif isinstance(value, datetime.date):
            # Convert date/datetime to MILLISECONDS-since-epoch (JS "new Date()").
            ms = time.mktime(value.utctimetuple()) * 1000
            ms += getattr(value, 'microseconds', 0) / 1000
            output[key] = int(ms)
        elif isinstance(value, db.GeoPt):
            output[key] = {'lat': value.lat, 'lon': value.lon}
        elif isinstance(value, db.Model):
            output[key] = to_dict(value)
        else:
            raise ValueError('cannot encode ' + repr(prop))

    return output
Run Code Online (Sandbox Code Playgroud)

  • 我没有尝试过所有可能的类型(日期,GeoPt,...),但似乎数据存储区确实有这种方法,到目前为止它一直在为字符串和整数工作:https://developers.google. com/appengine/docs/python/datastore/functions#to_dict所以我不确定你需要重新发明轮子来序列化为json:`json.dumps(db.to_dict(Photo))` (7认同)
  • 代码中有一个小错误:如果你有"output [key] = to_dict(model)",它应该是:"output [key] = to_dict(value)".除此之外,它是完美的.谢谢! (2认同)

mtg*_*red 60

这是我发现的最简单的解决方案.它只需要3行代码.

只需在模型中添加一个方法即可返回字典:

class DictModel(db.Model):
    def to_dict(self):
       return dict([(p, unicode(getattr(self, p))) for p in self.properties()])
Run Code Online (Sandbox Code Playgroud)

SimpleJSON现在可以正常工作:

class Photo(DictModel):
   filename = db.StringProperty()
   title = db.StringProperty()
   description = db.StringProperty(multiline=True)
   date_taken = db.DateTimeProperty()
   date_uploaded = db.DateTimeProperty(auto_now_add=True)
   album = db.ReferenceProperty(Album, collection_name='photo')

from django.utils import simplejson
from google.appengine.ext import webapp

class PhotoHandler(webapp.RequestHandler):
   def get(self):
      photos = Photo.all()
      self.response.out.write(simplejson.dumps([p.to_dict() for p in photos]))
Run Code Online (Sandbox Code Playgroud)


小智 15

在App Engine SDK的最新版本(1.5.2)中,to_dict()引入了将模型实例转换为字典的函数db.py.请参阅发行说明.

到目前为止,文档中没有引用此函数,但我自己尝试了它并且它按预期工作.

  • 对于ndb对象,self.to_dict()完成这项工作.如果你想通过标准的json模块使类可序列化,那么在类中添加'def default(self,o):return o.to_dict()` (2认同)

dpa*_*tru 7

要序列化模型,请添加自定义json编码器,如下面的python中所示:

import datetime
from google.appengine.api import users
from google.appengine.ext import db
from django.utils import simplejson

class jsonEncoder(simplejson.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()

        elif isinstance(obj, db.Model):
            return dict((p, getattr(obj, p)) 
                        for p in obj.properties())

        elif isinstance(obj, users.User):
            return obj.email()

        else:
            return simplejson.JSONEncoder.default(self, obj)


# use the encoder as: 
simplejson.dumps(model, cls=jsonEncoder)
Run Code Online (Sandbox Code Playgroud)

这将编码:

  • asoformat字符串的日期(根据此建议),
  • 作为其属性的词典的模型,
  • 用户作为他的电子邮件.

要解码日期,您可以使用此javascript:

function decodeJsonDate(s){
  return new Date( s.slice(0,19).replace('T',' ') + ' GMT' );
} // Note that this function truncates milliseconds.
Run Code Online (Sandbox Code Playgroud)

注意:感谢用户pydave编辑此代码以使其更具可读性.我最初使用python的if/else表达式jsonEncoder用更少的行表达如下:(我添加了一些注释并使用google.appengine.ext.db.to_dict,使其比原始更清晰.)

class jsonEncoder(simplejson.JSONEncoder):
  def default(self, obj):
    isa=lambda x: isinstance(obj, x) # isa(<type>)==True if obj is of type <type>
    return obj.isoformat() if isa(datetime.datetime) else \
           db.to_dict(obj) if isa(db.Model) else \
           obj.email()     if isa(users.User) else \
           simplejson.JSONEncoder.default(self, obj)
Run Code Online (Sandbox Code Playgroud)