Venho procurando há um bom tempo sem sucesso. Meu projeto não está usando Django, existe uma maneira simples de serializar modelos do App Engine (google.appengine.ext.db.Model) em JSON ou preciso escrever meu próprio 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
user111677
fonte
fonte
json.dumps(db.to_dict(Photo))
Esta é a solução mais simples que encontrei. Requer apenas 3 linhas de códigos.
Basta adicionar um método ao seu modelo para retornar um dicionário:
class DictModel(db.Model): def to_dict(self): return dict([(p, unicode(getattr(self, p))) for p in self.properties()])
SimpleJSON agora funciona corretamente:
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]))
fonte
Na versão mais recente (1.5.2) do SDK do App Engine, uma
to_dict()
função que converte instâncias de modelo em dicionários foi introduzida emdb.py
. Veja as notas de lançamento .Não há referência a essa função na documentação ainda, mas eu mesmo tentei e funciona conforme o esperado.
fonte
AttributeError: 'module' object has no attribute 'to_dict'
quando eufrom google.appengine.ext import db
usosimplejson.dumps(db.to_dict(r))
(onde r é uma instância de uma subclasse db.Model). Não vejo "to_dict" em google_appengine / google / appengine / ext / db / *Para serializar modelos, adicione um codificador json personalizado como no seguinte 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)
Isso irá codificar:
Para decodificar a data, você pode usar este javascript:
function decodeJsonDate(s){ return new Date( s.slice(0,19).replace('T',' ') + ' GMT' ); } // Note that this function truncates milliseconds.
Nota: Obrigado ao usuário pydave que editou este código para torná-lo mais legível. Eu tinha originalmente usado as expressões if / else do python para expressar
jsonEncoder
em menos linhas, como segue: (Eu adicionei alguns comentários e useigoogle.appengine.ext.db.to_dict
, para torná-lo mais claro do que o 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)
fonte
Você não precisa escrever seu próprio "analisador" (um analisador provavelmente transformaria JSON em um objeto Python), mas você ainda pode serializar seu objeto Python sozinho.
Usando o simplejson :
import simplejson as json serialized = json.dumps({ 'filename': self.filename, 'title': self.title, 'date_taken': date_taken.isoformat(), # etc. })
fonte
Para casos simples, gosto da abordagem defendida aqui no final do artigo:
# 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())})
O artigo também contém, na outra extremidade do espectro, uma classe serializadora complexa que enriquece o django (e requer
_meta
- não tenho certeza porque você está recebendo erros sobre _meta faltando, talvez o bug descrito aqui ) com a capacidade de serializar computado propriedades / métodos. Na maioria das vezes, você precisa de serialização em algum ponto intermediário, e para aqueles uma abordagem introspectiva como @David Wilson pode ser preferível.fonte
Mesmo se você não estiver usando o django como estrutura, essas bibliotecas ainda estão disponíveis para você usar.
from django.core import serializers data = serializers.serialize("xml", Photo.objects.all())
fonte
Se você usar app-engine-patch, ele declarará automaticamente o
_meta
atributo para você, e então você pode usardjango.core.serializers
como faria normalmente em modelos django (como no código do sledge).O patch do App-engine possui alguns outros recursos interessantes, como autenticação híbrida (django + contas do Google) e a parte administrativa do django funciona.
fonte
A resposta de Mtgred acima funcionou maravilhosamente para mim - modifiquei ligeiramente para que também pudesse obter a chave da entrada. Não como algumas linhas de código, mas me dá a chave ú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
fonte
Estendi a classe JSON Encoder escrita por dpatru para oferecer suporte a:
Propriedades de filtragem - apenas propriedades com um
verbose_name
serão codificadas em 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)
fonte
Conforme mencionado por https://stackoverflow.com/users/806432/fredva , o to_dict funciona muito bem. Aqui está o meu código que estou usando.
foos = query.fetch(10) prepJson = [] for f in foos: prepJson.append(db.to_dict(f)) myJson = json.dumps(prepJson))
fonte
Existe um método, "Model.properties ()", definido para todas as classes de Model. Ele retorna o dict que você procura.
from django.utils import simplejson class Photo(db.Model): # ... my_photo = Photo(...) simplejson.dumps(my_photo.properties())
Consulte as propriedades do modelo nos documentos.
fonte
TypeError: <google.appengine.ext.db.StringProperty object at 0x4694550> is not JSON serializable
Essas APIs (google.appengine.ext.db) não são mais recomendadas. Os aplicativos que usam essas APIs só podem ser executados no tempo de execução do App Engine Python 2 e precisarão migrar para outras APIs e serviços antes de migrar para o tempo de execução do App Engine Python 3. Para saber mais: clique aqui
fonte
Para serializar uma instância do Datastore Model, você não pode usar json.dumps (não testei, mas Lorenzo apontou). Talvez no futuro o seguinte 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)
fonte