如何将db.Model对象序列化为json?

时间:2010-01-22 02:53:42

标签: python google-app-engine simplejson

使用时

from django.utils import simplejson

对于从db.Model派生的类型的对象,它会抛出异常。如何规避这个?

5 个答案:

答案 0 :(得分:14)

好的 - 我的python不是很好所以任何帮助都会受到赞赏 - 你不需要编写解析器 - 这就是解决方案:

添加此类http://code.google.com/p/google-app-engine-samples/source/browse/trunk/geochat/json.py?r=55

 import datetime  
 import time 

 from google.appengine.api import users 
 from google.appengine.ext import db 

#this is a mod on the orinal file for some reason it includes its own simplejson files i have ref django!
 from django.utils import simplejson  

 class GqlEncoder(simplejson.JSONEncoder): 

   """Extends JSONEncoder to add support for GQL results and properties. 

   Adds support to simplejson JSONEncoders for GQL results and properties by 
   overriding JSONEncoder's default method. 
   """ 

   # TODO Improve coverage for all of App Engine's Property types. 

   def default(self, obj): 

     """Tests the input object, obj, to encode as JSON.""" 

     if hasattr(obj, '__json__'): 
       return getattr(obj, '__json__')() 

     if isinstance(obj, db.GqlQuery): 
       return list(obj) 

     elif isinstance(obj, db.Model): 
       properties = obj.properties().items() 
       output = {} 
       for field, value in properties: 
         output[field] = getattr(obj, field) 
       return output 

     elif isinstance(obj, datetime.datetime): 
       output = {} 
       fields = ['day', 'hour', 'microsecond', 'minute', 'month', 'second', 
           'year'] 
       methods = ['ctime', 'isocalendar', 'isoformat', 'isoweekday', 
           'timetuple'] 
       for field in fields: 
         output[field] = getattr(obj, field) 
       for method in methods: 
         output[method] = getattr(obj, method)() 
       output['epoch'] = time.mktime(obj.timetuple()) 
       return output 

     elif isinstance(obj, time.struct_time): 
       return list(obj) 

     elif isinstance(obj, users.User): 
       output = {} 
       methods = ['nickname', 'email', 'auth_domain'] 
       for method in methods: 
         output[method] = getattr(obj, method)() 
       return output 

     return simplejson.JSONEncoder.default(self, obj) 


 def encode(input): 
   """Encode an input GQL object as JSON 

     Args: 
       input: A GQL object or DB property. 

     Returns: 
       A JSON string based on the input object.  

     Raises: 
       TypeError: Typically occurs when an input object contains an unsupported 
         type. 
     """ 
   return GqlEncoder().encode(input)   

另存为json.py

使用

import cgi
import os
import json 

from google.appengine.ext.webapp import template
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db


class Greeting(db.Model):
    author = db.UserProperty()
    content = db.StringProperty(multiline=True)
    date = db.DateTimeProperty(auto_now_add=True)

class MainPage(webapp.RequestHandler):
    def get(self):
        greetings_query = Greeting.all().order('-date')
        greetings = greetings_query.fetch(5)

        if users.get_current_user():
            url = users.create_logout_url(self.request.uri)
            url_linktext = 'Logout'
        else:
            url = users.create_login_url(self.request.uri)
            url_linktext = 'Login'

        template_values = {
            'greetings': greetings,
            'url': url,
            'url_linktext': url_linktext,
            }

        path = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(path, template_values))


class Guestbook(webapp.RequestHandler):
    def post(self):
        greeting = Greeting()

        if users.get_current_user():
            greeting.author = users.get_current_user()

        greeting.content = self.request.get('content')
        greeting.put()
        self.redirect('/')



#here i return my json feed - simple implementaion for example
class FeedHandler(webapp.RequestHandler):

  def get(self):
    """Retrieve a feed"""
    user = None

    greetings_query = Greeting.all().order('-date')
    rs= greetings_query.fetch(5)
#this is the part that calls the encoder - dosnt cause an exception
    data = json.encode(rs)



#roll out to browser -might need to check my headers etc
    self.response.headers['Content-Type'] = 'application/json; charset=utf-8'  
    self.response.out.write(data)




application = webapp.WSGIApplication(
                                       [
                                       ('/', MainPage),
                                       ('/sign',Guestbook),
                                       ('/feed',FeedHandler),
                                       ], debug=True
                                    )

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()

这是浏览器响应:

  

[{“content”:“”,“date”:{“ctime”:“Sat Jan 23 02:40:22 2010”,“hour”:2,“isoweekday”:6,“month”:1 ,“秒”:22,“微秒”:434000,“isocalendar”:[2010,3,6],“timetuple”:[2010,1,23,2,40,22,5,23,-1], “年”:2010年,“epoch”:1264214422.0,“isoformat”:“2010-01-23T02:40:22.434000”,“day”:23,“分钟”:40},“作者”:{“昵称”: “test@example.com”,“email”:“test@example.com”,“auth_domain”:“gmail.com”}},{“content”:“”,“date”:{“ctime”:“ 1月23日星期六01:12:43“,”小时“:1,”isoweekday“:6,”月“:1,”秒“:43,”微秒“:972000,”isocalendar“:[2010,3, 6],“timetuple”:[2010,1,23,1,12,43,5,23,-1],“年”:2010年,“epoch”:1264209163.0,“isoformat”:“2010-01-23T01 :12:43.972000“,”day“:23,”分钟“:12},”作者“:{”昵称“:”test@example.com“,”email“:”test@example.com“,”auth_domain “:”gmail.com“}},{”content“:”test“,”date“:{”ctime“:”Fri Jan 22 22:32:13 2010“,”hour“:22,”isoweekday“: 5,“月”:1,“秒”:13,“微秒”:659000, “isocalendar”:[2010,3,5],“timetuple”:[2010,1,22,22,32,13,4,22,-1],“年”:2010年,“epoch”:1264199533.0,“ isoformat“:”2010-01-22T22:32:13.659000“,”day“:22,”分钟“:32},”作者“:{”昵称“:”test@example.com“,”email“:” test@example.com“,”“auth_domain”:“gmail.com”}},{“content”:“”,“date”:{“ctime”:“Fri Jan 22 22:29:49 2010”,“hour” “:22,”isoweekday“:5,”month“:1,”second“:49,”microsecond“:358000,”isocalendar“:[2010,3,5],”timetuple“:[2010,1,22 ,22,29,49,4,22,-1],“年”:2010年,“epoch”:1264199389.0,“isoformat”:“2010-01-22T22:29:49.358000”,“day”:22,“分钟“:29},”作者“:{”昵称“:”test@example.com“,”email“:”test@example.com“,”auth_domain“:”gmail.com“}},{”content “:”啊它有效!\ r \ n“,”date“:{”ctime“:”Fri Jan 22 22:29:22 2010“,”hour“:22,”isoweekday“:5,”month“: 1,“秒”:22,“微秒”:995000,“isocalendar”:[2010,3,5],“timetuple”:[2010,1,22,22,29,22,4,22,-1] ,“年”:2010年,“纪元”:1264199362.0,“isoformat” :“2010-01-22T22:29:22.995000”,“day”:22,“分钟”:29},“作者”:{“昵称”:“test@example.com”,“email”:“test @ example.com“,”auth_domain“:”gmail.com“}}]

答案 1 :(得分:10)

Jader Dias提供的例子在经历了一些麻烦之后对我的关注很好。删除编码方法,因为它包含循环引用。调整后的课程应如下所示:

import datetime  
import time 

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


class GqlEncoder(simplejson.JSONEncoder): 

    """Extends JSONEncoder to add support for GQL results and properties. 

    Adds support to simplejson JSONEncoders for GQL results and properties by 
    overriding JSONEncoder's default method. 
    """ 

    # TODO Improve coverage for all of App Engine's Property types. 

    def default(self, obj): 

        """Tests the input object, obj, to encode as JSON.""" 

        if hasattr(obj, '__json__'): 
            return getattr(obj, '__json__')() 

        if isinstance(obj, db.GqlQuery): 
            return list(obj) 

        elif isinstance(obj, db.Model): 
            properties = obj.properties().items() 
            output = {} 
            for field, value in properties: 
                output[field] = getattr(obj, field) 
            return output 

        elif isinstance(obj, datetime.datetime): 
            output = {} 
            fields = ['day', 'hour', 'microsecond', 'minute', 'month', 'second', 'year'] 
            methods = ['ctime', 'isocalendar', 'isoformat', 'isoweekday', 'timetuple'] 
            for field in fields: 
                output[field] = getattr(obj, field) 
            for method in methods: 
                output[method] = getattr(obj, method)() 
            output['epoch'] = time.mktime(obj.timetuple()) 
            return output

        elif isinstance(obj, datetime.date): 
            output = {} 
            fields = ['year', 'month', 'day'] 
            methods = ['ctime', 'isocalendar', 'isoformat', 'isoweekday', 'timetuple'] 
            for field in fields: 
                output[field] = getattr(obj, field) 
            for method in methods: 
                output[method] = getattr(obj, method)() 
            output['epoch'] = time.mktime(obj.timetuple()) 
            return output 

        elif isinstance(obj, time.struct_time): 
            return list(obj) 

        elif isinstance(obj, users.User): 
            output = {} 
            methods = ['nickname', 'email', 'auth_domain'] 
            for method in methods: 
                output[method] = getattr(obj, method)() 
            return output 

        return simplejson.JSONEncoder.default(self, obj) 

因为我已将此类保存在名为utils.py的文件中,并在适当时使用

导入它
import utils

然后我只调用utils.GqlEncoder()。encode(results),例如:

query = User.all()
results = query.fetch(10)

self.response.headers['Content-Type'] = "text/plain" # Alt. application/json
self.response.out.write( utils.GqlEncoder().encode(results) )

结果看起来应该是这样的(我添加了一些换行符以便更容易阅读):

[
{"date": {"ctime": "Tue Feb 23 10:41:21 2010", "hour": 10, "isoweekday": 2, "month": 2, 
        "second": 21, "microsecond": 495535, "isocalendar": [2010, 8, 2], "timetuple": [2010, 2, 23, 10, 41, 21, 1, 54, -1], 
        "year": 2010, "epoch": 1266921681.0, "isoformat": "2010-02-23T10:41:21.495535", "day": 23, "minute": 41}, 
"claimed_id": "https:\/\/www.google.com\/accounts\/o8\/id?id=abcdefghijklmnopqrstuvxyz", 
"display_name": "Alfred E Neumann", 
"email": null, 
"full_name": "Alfred E Neumann"
}, 
{"date": {"ctime": "Tue Feb 23 11:00:54 2010", "hour": 11, "isoweekday": 2, "month": 2, 
        "second": 54, "microsecond": 805261, "isocalendar": [2010, 8, 2], "timetuple": [2010, 2, 23, 11, 0, 54, 1, 54, -1], 
        "year": 2010, "epoch": 1266922854.0, "isoformat": "2010-02-23T11:00:54.805261", "day": 23, "minute": 0}, 
"claimed_id": "http:\/\/openid.domain.net\/john", 
"display_name": "", 
"email": "jp@domain.net", 
"full_name": "John Parnefjord"
}
]

答案 2 :(得分:3)

json不能用于序列化除基本类型之外的任何内容,例如dicts,lists,ints / longs和strings(这不是全面的)。例如,即使这些简单的命令也不起作用:

import json
json.dumps(object())

如果你想序列化django对象,你应该参考django documentation on serialization,它将使用自己的库,但它们确实支持json。

答案 3 :(得分:0)

由于我找不到合适的解决方案,我编写了自己的解决方案,这不是JSON序列化程序,而是Javascript序列化程序

from google.appengine.ext import db
from google.appengine.api.datastore_types import *

def dumpStr(obj):
    return "'" + obj + "'"

def dumps(obj):
    if isinstance(obj, str):
        return dumpStr(obj)
    elif obj == None:
        return None
    elif isinstance(obj, list):
        items = [];
        for item in obj:
            items.append(dumps(item))
        return '[' + ','.join(items) + ']'
    elif isinstance(obj, datetime.datetime):
        return "new Date('%s')" % obj.ctime()
    properties = [];
    for property in dir(obj):
        if property[0] != '_':
            value = obj.__getattribute__(property)
            valueClass = str(value.__class__)
            if not(('function' in valueClass) or ('built' in valueClass) or ('method' in valueClass)):
                value = dumps(value)
                if value != None:
                    properties.append("'" + property + "':" + value)
    if len(properties) == 0:
        return str(obj)
    else:
        return '{' + ','.join(properties) + '}'

答案 4 :(得分:-1)

从我能理解的 - 我是python的新手 - 使用谷歌应用引擎,解决方法是将模型对象序列化为dictioanry python对象,然后使用简单的json将其转储为json字符串 - 这不会对我来说很有意义 - 也许有人知道要联系到ditionary(pickel?) 任何有关这方面的帮助都将是帮助!不要忘了谷歌应用程序引擎没有内置的解决方案。