He estado buscando durante bastante tiempo sin éxito. Mi proyecto no usa Django, ¿existe una forma sencilla de serializar los modelos de App Engine (google.appengine.ext.db.Model) en JSON o necesito escribir mi propio serializador?
Modelo:
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')
python
json
google-app-engine
usuario111677
fuente
fuente
json.dumps(db.to_dict(Photo))
Esta es la solución más simple que encontré. Requiere solo 3 líneas de códigos.
Simplemente agregue un método a su modelo para devolver un diccionario:
class DictModel(db.Model): def to_dict(self): return dict([(p, unicode(getattr(self, p))) for p in self.properties()])
SimpleJSON ahora funciona correctamente:
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]))
fuente
En la última versión (1.5.2) del SDK de App Engine,
to_dict()
se introdujo una función que convierte instancias de modelo en diccionariosdb.py
. Consulte las notas de la versión .No hay ninguna referencia a esta función en la documentación hasta el momento, pero la he probado yo mismo y funciona como se esperaba.
fuente
AttributeError: 'module' object has no attribute 'to_dict'
cuando Ifrom google.appengine.ext import db
y usosimplejson.dumps(db.to_dict(r))
(donde r es una instancia de una subclase db.Model). No veo "to_dict" en google_appengine / google / appengine / ext / db / *Para serializar modelos, agregue un codificador json personalizado como en el siguiente 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)
Esto codificará:
Para decodificar la fecha puedes usar este javascript:
function decodeJsonDate(s){ return new Date( s.slice(0,19).replace('T',' ') + ' GMT' ); } // Note that this function truncates milliseconds.
Nota: Gracias al usuario pydave que editó este código para hacerlo más legible. Originalmente había usado las expresiones if / else de python para expresar
jsonEncoder
en menos líneas de la siguiente manera: (agregué algunos comentarios y uségoogle.appengine.ext.db.to_dict
, para hacerlo más claro que el original).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)
fuente
No necesitas escribir tu propio "analizador" (un analizador presumiblemente convertiría JSON en un objeto Python), pero aún puedes serializar tu objeto Python tú mismo.
Usando simplejson :
import simplejson as json serialized = json.dumps({ 'filename': self.filename, 'title': self.title, 'date_taken': date_taken.isoformat(), # etc. })
fuente
Para casos simples, me gusta el enfoque propuesto aquí al final del artículo:
# after obtaining a list of entities in some way, e.g.: user = users.get_current_user().email().lower(); col = models.Entity.gql('WHERE user=:1',user).fetch(300, 0) # ...you can make a json serialization of name/key pairs as follows: json = simplejson.dumps(col, default=lambda o: {o.name :str(o.key())})
El artículo también contiene, en el otro extremo del espectro, una clase de serializador compleja que enriquece la de django (y requiere
_meta
, no estoy seguro de por qué está obteniendo errores sobre la falta de _meta, tal vez el error descrito aquí ) con la capacidad de serializar calculado propiedades / métodos. La mayoría de las veces, las necesidades de serialización se encuentran en algún punto intermedio, y para aquellos, puede ser preferible un enfoque introspectivo como el de @David Wilson.fuente
Incluso si no está utilizando django como marco, esas bibliotecas todavía están disponibles para su uso.
from django.core import serializers data = serializers.serialize("xml", Photo.objects.all())
fuente
Si usa app-engine-patch , declarará automáticamente el
_meta
atributo y luego podrá usardjango.core.serializers
como lo haría normalmente en los modelos de django (como en el código de sledge).App-engine-patch tiene algunas otras características interesantes, como una autenticación híbrida (cuentas de django + google), y la parte de administración de django funciona.
fuente
La respuesta de Mtgred anterior funcionó de maravilla para mí: la modifiqué ligeramente para que también pudiera obtener la clave para la entrada. No como pocas líneas de código, pero me da la clave única:
class DictModel(db.Model): def to_dict(self): tempdict1 = dict([(p, unicode(getattr(self, p))) for p in self.properties()]) tempdict2 = {'key':unicode(self.key())} tempdict1.update(tempdict2) return tempdict1
fuente
He extendido la clase JSON Encoder escrita por dpatru para admitir:
Propiedades de filtrado: solo las propiedades con un
verbose_name
se codificarán en JSONclass DBModelJSONEncoder(json.JSONEncoder): """Encodes a db.Model into JSON""" def default(self, obj): if (isinstance(obj, db.Query)): # It's a reference query (holding several model instances) return [self.default(item) for item in obj] elif (isinstance(obj, db.Model)): # Only properties with a verbose name will be displayed in the JSON output properties = obj.properties() filtered_properties = filter(lambda p: properties[p].verbose_name != None, properties) # Turn each property of the DB model into a JSON-serializeable entity json_dict = dict([( p, getattr(obj, p) if (not isinstance(getattr(obj, p), db.Model)) else self.default(getattr(obj, p)) # A referenced model property ) for p in filtered_properties]) json_dict['id'] = obj.key().id() # Add the model instance's ID (optional - delete this if you do not use it) return json_dict else: # Use original JSON encoding return json.JSONEncoder.default(self, obj)
fuente
Como lo menciona https://stackoverflow.com/users/806432/fredva , el to_dict funciona muy bien. Aquí está mi código que estoy usando.
foos = query.fetch(10) prepJson = [] for f in foos: prepJson.append(db.to_dict(f)) myJson = json.dumps(prepJson))
fuente
Hay un método, "Model.properties ()", definido para todas las clases de modelos. Devuelve el dict que buscas.
from django.utils import simplejson class Photo(db.Model): # ... my_photo = Photo(...) simplejson.dumps(my_photo.properties())
Consulte Propiedades del modelo en los documentos.
fuente
TypeError: <google.appengine.ext.db.StringProperty object at 0x4694550> is not JSON serializable
Estas API (google.appengine.ext.db) ya no se recomiendan. Las aplicaciones que usan estas API solo pueden ejecutarse en el tiempo de ejecución de App Engine Python 2 y deberán migrar a otras API y servicios antes de migrar al tiempo de ejecución de App Engine Python 3. Para saber más: haga clic aquí
fuente
Para serializar una instancia de modelo de almacén de datos, no puede usar json.dumps (no lo he probado, pero Lorenzo lo señaló). Quizás en el futuro lo siguiente funcione.
http://docs.python.org/2/library/json.html
import json string = json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) object = json.loads(self.request.body)
fuente