При использовании
from django.utils import simplejson
на объектах типов, которые выводятся из db.Model
, он генерирует исключения. Как обойти это?
При использовании
from django.utils import simplejson
на объектах типов, которые выводятся из db.Model
, он генерирует исключения. Как обойти это?
Так как я не мог найти подходящее решение, я написал свой собственный, что не является точно сериализатором 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) + '}'
Хорошо - мой питон невелик, поэтому любая помощь будет оценена - вам не нужно писать парсер - это решение:
добавить этот класс utlity 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 default method.
"""
# TODO Improve coverage for all of App Engine 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 ":" Сб янв 23 02:40:22 2010 "," час ": 2," isoweekday ": 6," month ": 1," второй ": 22," microsecond ": 434000, "isocalendar": [2010, 3, 6], "timetuple": [2010, 1, 23, 2, 40, 22, 5, 23, -1]" год ": 2010," эпоха ": 1264214422.0," isoformat ":" 2010-01-23T02: 40: 22.434000 "," день ": 23," минута ": 40}," автор ": {" ник ":" [email protected] "," email ":" [email protected] "," auth_domain ":" gmail.com"}}, { "content": "," date ": {" ctime ":" Сб Янв 23 01:12:43 2010 "," час ": 1," isoweekday ": 6," месяц ": 1," второй ": 43," microsecond ": 972000," isocalendar ": [2010, 3, 6], "timetuple": [2010, 1, 23, 1, 12, 43, 5, 23, -1]," год ": 2010," эпоха ": 1264209163.0," isoformat ":" 2010-01-23T01:12: 43.972000 "," day ": 23," minute ": 12}," author ": {" nickname ":" [email protected] "," email ":" [email protected] "," auth_domain ":" gmail.com "}}, {" content ":" test "," date ": {" ctime ":" Пятница 22 января 22:32:13 2010 "," час ": 22," isoweekday ": 5," месяц ": 1," второй ": 13," микросекунда ": 659000, "isocalendar": [2010, 3, 5], "timetuple": [2010, 1, 22, 22, 32, 13, 4, 22, -1]," year ": 2010," epoch": 1264199533.0, isoformat ":" 2010-01-22T22: 32: 13.659000 "," day ": 22," minute ": 32}," author ": {" nickname ":" [email protected] "," email ":" [email protected] "," auth_domain ":" gmail.com "}}, {" content ":" "," date ": {" ctime ":" Пт 22 янв 22:29:49 2010 "," час ": 22," isoweekday ": 5," месяц ": 1," второй ": 49, "microsecond": 358000, "isocalendar": [2010, 3, 5], "timetuple": [2010, 1, 22, 22, 29, 49, 4, 22, -1], "год ": 2010," эпоха": 1264199389.0, "изоформат ":" 2010-01-22T22: 29: 49.358000 "," день": 22, минута ": 29}," автор ": {" nickname ":" [email protected] "," email ":" [email protected] "," auth_domain ":" gmail.com "}}, {" content ":" ah it works!\r\n "," date ": {" ctime ":" Пт Янв 22 22:29:22 2010 "," час ": 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 "," день ": 22," минута ": 29}," автор ": {" ник ":" [email protected] "," email ":" test @example.com "," auth_domain ":" gmail.com "}}]
Пример, представленный 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 default method.
"""
# TODO Improve coverage for all of App Engine 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": "[email protected]",
"full_name": "John Parnefjord"
}
]
json не может использоваться для сериализации чего-либо большего, чем базовые типы, такие как dicts, lists, ints/longs и strings (это не является исчерпывающим). Например, даже эти простые команды не работают:
import json
json.dumps(object())
Если вы хотите сериализовать объекты django, вы должны обратиться к документации django по сериализации, которая будет использовать свои собственные библиотеки, но они действительно поддерживают json.
Из того, что я могу понять - и я новичок в python - с движком google-приложений работа над сериализацией объекта модели на объект python dictioanry, а затем использовать простой json для сбрасывания его как строки json - это не делает смысл для меня - может быть, кто-то знает сериализовать к ditionary (pickel?) Любая помощь по этому поводу - ПОМОЩЬ! чтобы не впечатлило, что для этого движка Google не существует встроенного решения.