Szukałem od dłuższego czasu bezskutecznie. Mój projekt nie używa Django, czy istnieje prosty sposób na serializowanie modeli App Engine (google.appengine.ext.db.Model) do JSON, czy też muszę napisać własny serializator?
Model:
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
źródło
źródło
json.dumps(db.to_dict(Photo))
To najprostsze rozwiązanie, jakie znalazłem. Wymaga tylko 3 wierszy kodów.
Po prostu dodaj metodę do swojego modelu, aby zwrócić słownik:
class DictModel(db.Model): def to_dict(self): return dict([(p, unicode(getattr(self, p))) for p in self.properties()])
SimpleJSON działa teraz poprawnie:
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]))
źródło
W najnowszej (1.5.2) wersji zestawu SDK App Engine wprowadzono
to_dict()
funkcję konwertującą instancje modelu na słowniki wdb.py
. Zobacz informacje o wersji .Na razie w dokumentacji nie ma odniesienia do tej funkcji, ale wypróbowałem ją sam i działa zgodnie z oczekiwaniami.
źródło
AttributeError: 'module' object has no attribute 'to_dict'
gdyfrom google.appengine.ext import db
i używamsimplejson.dumps(db.to_dict(r))
(gdzie r jest wystąpieniem podklasy db.Model). Nie widzę "to_dict" w google_appengine / google / AppEngine / ext / db / *Aby serializować modele, dodaj niestandardowy koder json, jak w następującym języku 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)
To zakoduje:
Aby odszyfrować datę, możesz użyć tego javascript:
function decodeJsonDate(s){ return new Date( s.slice(0,19).replace('T',' ') + ' GMT' ); } // Note that this function truncates milliseconds.
Uwaga: Dziękujemy użytkownikowi pydave, który zmodyfikował ten kod, aby był bardziej czytelny. Pierwotnie użyłem wyrażeń if / else języka Python do wyrażenia
jsonEncoder
w mniejszej liczbie wierszy w następujący sposób: (Dodałem kilka komentarzy i użyłemgoogle.appengine.ext.db.to_dict
, aby uczynić je bardziej przejrzystymi niż oryginał).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)
źródło
Nie musisz pisać własnego „parsera” (parser prawdopodobnie zmieniłby JSON w obiekt Pythona), ale nadal możesz samemu serializować swój obiekt Pythona.
Korzystanie z simplejson :
import simplejson as json serialized = json.dumps({ 'filename': self.filename, 'title': self.title, 'date_taken': date_taken.isoformat(), # etc. })
źródło
W prostych przypadkach, lubię podejściem zalecanym tu na końcu artykułu:
# 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())})
Artykuł zawiera również, na drugim końcu spektrum, złożoną klasę serializatora, która wzbogaca django (i wymaga
_meta
- nie wiem, dlaczego otrzymujesz błędy dotyczące braku _meta, być może opisanego tutaj błędu ) z możliwością serializacji obliczonej właściwości / metody. W większości przypadków potrzeby serializacji leżą gdzieś pomiędzy, a dla tych bardziej introspektywne podejście, takie jak @David Wilson, może być preferowane.źródło
Nawet jeśli nie używasz django jako frameworka, te biblioteki są nadal dostępne do użycia.
from django.core import serializers data = serializers.serialize("xml", Photo.objects.all())
źródło
Jeśli używasz app-engine-patch , automatycznie zadeklaruje on
_meta
atrybut za Ciebie, a następnie możesz go używaćdjango.core.serializers
tak, jak zwykle robisz to na modelach django (jak w kodzie sledge).App-engine-patch ma kilka innych fajnych funkcji, takich jak uwierzytelnianie hybrydowe (konta django + Google), a część administracyjna django działa.
źródło
Powyższa odpowiedź Mtgred zadziałała wspaniale dla mnie - nieznacznie ją zmodyfikowałem, więc mogłem również uzyskać klucz do wpisu. Nie tylko kilka wierszy kodu, ale daje mi unikalny klucz:
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
źródło
Rozszerzyłem klasę JSON Encoder napisaną przez dpatru do obsługi:
Właściwości filtrowania - tylko właściwości z a
verbose_name
zostaną zakodowane w formacie 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)
źródło
Jak wspomniano w https://stackoverflow.com/users/806432/fredva , to_dict działa świetnie. Oto mój kod, którego używam.
foos = query.fetch(10) prepJson = [] for f in foos: prepJson.append(db.to_dict(f)) myJson = json.dumps(prepJson))
źródło
Istnieje metoda „Model.properties ()” zdefiniowana dla wszystkich klas Model. Zwraca dykt, którego szukasz.
from django.utils import simplejson class Photo(db.Model): # ... my_photo = Photo(...) simplejson.dumps(my_photo.properties())
Zobacz Właściwości modelu w dokumentacji.
źródło
TypeError: <google.appengine.ext.db.StringProperty object at 0x4694550> is not JSON serializable
Te interfejsy API (google.appengine.ext.db) nie są już zalecane. Aplikacje korzystające z tych interfejsów API mogą działać tylko w środowisku wykonawczym App Engine Python 2 i przed migracją do środowiska wykonawczego App Engine Python 3 będą musiały przejść na inne interfejsy API i usługi. Aby dowiedzieć się więcej: kliknij tutaj
źródło
Aby serializować instancję Datastore Model, nie możesz użyć json.dumps (nie testowano, ale Lorenzo to wskazał). Może w przyszłości zadziała poniższe.
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)
źródło