Django verfügt über eine gute automatische Serialisierung von ORM-Modellen, die von DB in das JSON-Format zurückgegeben wurden.
Wie serialisiere ich das SQLAlchemy-Abfrageergebnis in das JSON-Format?
Ich habe es versucht, jsonpickle.encode
aber es codiert das Abfrageobjekt selbst. Ich habe es versucht, json.dumps(items)
aber es kehrt zurück
TypeError: <Product('3', 'some name', 'some desc')> is not JSON serializable
Ist es wirklich so schwierig, SQLAlchemy ORM-Objekte in JSON / XML zu serialisieren? Gibt es keinen Standard-Serializer dafür? Heutzutage ist es eine sehr häufige Aufgabe, ORM-Abfrageergebnisse zu serialisieren.
Ich muss lediglich die JSON- oder XML-Datendarstellung des SQLAlchemy-Abfrageergebnisses zurückgeben.
Das Abfrageergebnis von SQLAlchemy-Objekten im JSON / XML-Format wird benötigt, um in Javascript-Datagird (JQGrid http://www.trirand.com/blog/ ) verwendet zu werden.
quelle
Antworten:
Eine flache Implementierung
Sie könnten so etwas verwenden:
und konvertieren Sie dann in JSON mit:
Felder, die nicht codierbar sind, werden ignoriert (setzen Sie sie auf 'Keine').
Beziehungen werden nicht automatisch erweitert (da dies zu Selbstreferenzen führen und für immer eine Schleife bilden kann).
Eine rekursive, nicht zirkuläre Implementierung
Wenn Sie jedoch lieber für immer eine Schleife erstellen möchten, können Sie Folgendes verwenden:
Und dann codieren Sie Objekte mit:
Dies würde alle Kinder und alle ihre Kinder und alle ihre Kinder codieren ... Im Grunde genommen möglicherweise Ihre gesamte Datenbank codieren. Wenn es etwas erreicht, das zuvor codiert wurde, wird es als "Keine" codiert.
Eine rekursive, möglicherweise kreisförmige, selektive Implementierung
Eine andere Alternative, wahrscheinlich besser, besteht darin, die Felder angeben zu können, die Sie erweitern möchten:
Sie können es jetzt aufrufen mit:
Zum Beispiel nur um SQLAlchemy-Felder zu erweitern, die als "Eltern" bezeichnet werden.
quelle
online_order
und habeaddress
, beide mit einer Beziehung zuuser
, aberonline_order
auch eine Beziehung zuaddress
. Wenn ich all dies serialisieren wollte, müsste ich esaddress
in das aufnehmenfields_to_expand
, aber ich möchte esaddress
aufgrund seiner Beziehung zuuser
und nicht redundant serialisierenonline_order
.for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
so, dass es angezeigt wirdfor field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata' and not x.startswith('query')]:
. Denken Sie daran, dass diese Lösung verhindert, dass Sie eine Eigenschaft / Beziehung mit dem Namen 'query' habenSie können Ihr Objekt einfach als Wörterbuch ausgeben:
Und dann benutzt du
User.as_dict()
um Ihr Objekt zu serialisieren.Wie unter Konvertieren des SQLlchemie-Zeilenobjekts in Python-Diktat erläutert
quelle
JSONEncoder
Objekts. Sie können eine Unterklasse erstellen, um Ihren eigenen Encoder für ein Objekt zu definieren, einschließlich datetime. Beachten Sie, dassFlask
beispielsweise die sofortige Codierung von datetime in JSON (mit der neuesten Version) unterstützt wird.return {c.name: unicode(getattr(self, c.name)) for c in self.__table__.columns}
Sie können einen RowProxy in ein Diktat wie das folgende konvertieren:
Serialisieren Sie das dann in JSON (Sie müssen einen Encoder für Dinge wie
datetime
Werte angeben ). Es ist nicht so schwer, wenn Sie nur einen Datensatz (und keine vollständige Hierarchie verwandter Datensätze) möchten.quelle
Ich empfehle Marshmallow . Sie können Serializer erstellen, um Ihre Modellinstanzen mit Unterstützung für Beziehungen und verschachtelte Objekte darzustellen.
Hier ist ein abgeschnittenes Beispiel aus ihren Dokumenten. Nehmen Sie das ORM-Modell
Author
:Ein Marshmallow-Schema für diese Klasse ist wie folgt aufgebaut:
... und so verwendet:
... würde eine Ausgabe wie diese erzeugen:
Schauen Sie sich das vollständige Flask-SQLAlchemy-Beispiel an .
Eine Bibliothek namens
marshmallow-sqlalchemy
SQLAlchemy und Marshmallow integriert speziell. In dieser BibliothekAuthor
sieht das Schema für das oben beschriebene Modell folgendermaßen aus:Durch die Integration können die Feldtypen aus den SQLAlchemy-
Column
Typen abgeleitet werden.Marshmallow-Sqlalchemie hier.
quelle
Python 3.7+ und Flask 1.1+ können den Einbau-verwenden dataclasses Paket
Die
/users/
Route gibt nun eine Liste der Benutzer zurück.Verwandte Modelle automatisch serialisieren
Die Antwort von
jsonify(account)
wäre dies.Überschreiben Sie den Standard-JSON-Encoder
quelle
data = request.json['user']; user = User(**data)
id: int = Column
funktioniert, aberid = Column
nicht. Es scheint, als müssten Sie die statische Eingabe für den JSON deklarieren, um das Feld zu serialisieren. Andernfalls erhalten Sie ein leeres{}
Objekt.pipenv install dataclasses
. Und dann wird es gut funktionieren.Das Flask-JsonTools- Paket enthält eine Implementierung von JsonSerializableBase für Ihre Modelle.
Verwendung:
Jetzt die
User
Modell magisch serialisierbar.Wenn Ihr Framework nicht Flask ist, können Sie einfach den Code abrufen
quelle
import flask.ext.whatever
dies in Flask 1.0 nicht mehr unterstützt wird.Aus Sicherheitsgründen sollten Sie niemals alle Felder des Modells zurückgeben. Ich ziehe es vor, sie selektiv auszuwählen.
Die json-Codierung von Flask unterstützt jetzt UUID, Datum / Uhrzeit und Beziehungen (und hinzugefügt
query
undquery_class
für diedb.Model
Klasse flask_sqlalchemy ). Ich habe den Encoder wie folgt aktualisiert:Damit kann ich optional eine
__json__
Eigenschaft hinzufügen , die die Liste der Felder zurückgibt, die ich codieren möchte:Ich füge meiner Ansicht @jsonapi hinzu, gebe die Ergebnisliste zurück und meine Ausgabe lautet dann wie folgt:
quelle
@jsonapi
zu@app.route
in views.py etc), aber ich liebe die Einfachheit davon. Ich denke, es ist billig Flask hinzugefügt Datum / Uhrzeit, aber nicht Datum, also habe ich es selbst zu json_encoder.py hinzugefügt :value=...
^if isinstance(value, date):
^data[field] = datetime.combine(value, time.min).isoformat()
^else:
^try:...
Sie können die Introspektion von SqlAlchemy wie folgt verwenden:
Lassen Sie sich von einer Antwort hier inspirieren: Konvertieren Sie das Zeilenobjekt sqlalchemy in python dict
quelle
Eine detailliertere Erklärung. Fügen Sie in Ihrem Modell Folgendes hinzu:
Das
str()
ist für Python 3, also wenn Sie Python 2 verwenden, verwenden Sieunicode()
. Es sollte helfen, Daten zu deserialisieren. Sie können es entfernen, wenn Sie sich nicht mit diesen befassen.Sie können die Datenbank jetzt wie folgt abfragen
First()
wird benötigt, um seltsame Fehler zu vermeiden.as_dict()
wird nun das Ergebnis deserialisieren. Nach der Deserialisierung kann es an json übergeben werdenquelle
Es ist nicht so einfach. Ich habe dazu einen Code geschrieben. Ich arbeite noch daran und es verwendet das MochiKit-Framework. Grundsätzlich werden zusammengesetzte Objekte zwischen Python und Javascript mithilfe eines Proxys und registrierter JSON-Konverter übersetzt.
Die Browserseite für Datenbankobjekte ist db.js. Sie benötigt die grundlegende Python- Proxyquelle in proxy.js .
Auf der Python-Seite befindet sich das Basis- Proxy-Modul . Dann endlich der SqlAlchemy-Objektcodierer in webserver.py . Dies hängt auch von den Metadatenextraktoren in der Datei models.py ab .
quelle
Während die ursprüngliche Frage eine Weile zurückreicht, deuten die Anzahl der Antworten hier (und meine eigenen Erfahrungen) darauf hin, dass es sich um eine nicht triviale Frage mit vielen verschiedenen Ansätzen unterschiedlicher Komplexität und unterschiedlichen Kompromissen handelt.
Aus diesem Grund habe ich die SQLAthanor- Bibliothek erstellt, die das deklarative ORM von SQLAlchemy um konfigurierbare Unterstützung für Serialisierung / De-Serialisierung erweitert, die Sie sich vielleicht ansehen möchten.
Die Bibliothek unterstützt:
dict
password
Wert unterstützen, aber niemals einen ausgehenden Wert einschließen )Sie können die (ich hoffe!) Umfassenden Dokumente hier einsehen: https://sqlathanor.readthedocs.io/en/latest
Hoffe das hilft!
quelle
Benutzerdefinierte Serialisierung und Deserialisierung.
"from_json" (Klassenmethode) erstellt ein basierend auf JSON-Daten.
"deserialize" kann nur für eine Instanz aufgerufen werden und alle Daten von json in die Model-Instanz zusammenführen.
"serialize" - rekursive Serialisierung
Die Eigenschaft __write_only__ wird benötigt, um Nur-Schreib-Eigenschaften zu definieren (z. B. "password_hash").
quelle
Hier ist eine Lösung, mit der Sie die Beziehungen, die Sie in Ihre Ausgabe aufnehmen möchten, so tief auswählen können, wie Sie möchten. HINWEIS: Dies ist ein vollständiges Umschreiben, bei dem ein Diktat / Str als Argument und nicht als Liste verwendet wird. behebt einige Sachen ..
Also für ein Beispiel mit Person / Familie / Zuhause / Zimmer ... verwandeln Sie es in json alles was Sie brauchen ist
quelle
Ich dachte, ich würde mit diesem ein bisschen Code Golf spielen.
Zu Ihrer Information : Ich verwende automap_base da wir ein separat gestaltetes Schema haben, das den Geschäftsanforderungen entspricht. Ich habe gerade erst angefangen, SQLAlchemy zu verwenden, aber die Dokumentation besagt, dass automap_base eine Erweiterung von declarative_base ist, was das typische Paradigma im SQLAlchemy ORM zu sein scheint. Ich glaube, dass dies funktionieren sollte.
Das Befolgen von Fremdschlüsseln gemäß der Lösung von Tjorriemorrie macht keine Lust , aber es ordnet Spalten einfach Werten zu und behandelt Python-Typen, indem es die Spaltenwerte str () -. Unsere Werte bestehen aus Python datetime.time und decimal.Decimal-Klassentypergebnissen, damit die Aufgabe erledigt wird.
Hoffe das hilft allen Passanten!
quelle
Ich weiß, dass dies ein ziemlich älterer Beitrag ist. Ich nahm die von @SashaB gegebene Lösung und modifizierte sie gemäß meinen Anforderungen.
Ich habe folgende Dinge hinzugefügt:
Mein Code lautet wie folgt:
Hoffe es hilft jemandem!
quelle
Verwenden Sie den in SQLAlchemy integrierten Serializer :
Wenn Sie das Objekt zwischen Sitzungen übertragen, denken Sie daran, das Objekt mithilfe von von der aktuellen Sitzung zu trennen
session.expunge(obj)
. Um es wieder anzubringen, tun Sie es einfachsession.add(obj)
.quelle
Der folgende Code serialisiert das Ergebnis von sqlalchemy in json.
Spaß nennen,
quelle
Der AlchemyEncoder ist wunderbar, schlägt aber manchmal mit Dezimalwerten fehl. Hier ist ein verbesserter Encoder, der das Dezimalproblem löst -
quelle
Wenn Sie mit sqlalchemy eine Verbindung zu einer Datenbank herstellen, ist dies eine einfache Lösung, die in hohem Maße konfigurierbar ist. Verwenden Sie Pandas.
quelle
Unter Flask funktioniert dies und verarbeitet Datenzeitfelder, wobei ein Feld vom Typ
'time': datetime.datetime(2018, 3, 22, 15, 40)
in Folgendes umgewandelt wird"time": "2018-03-22 15:40:00"
:quelle
Die eingebauten Serializer-Drosseln mit utf-8 können für einige Eingaben kein ungültiges Startbyte dekodieren. Stattdessen ging ich mit:
quelle
Vielleicht können Sie eine Klasse wie diese verwenden
Damit haben alle Objekte die
to_dict
Methodequelle
Während ich einige unformatierte SQL- und undefinierte Objekte verwendete,
cursor.description
schien die Verwendung das zu bekommen, wonach ich suchte:quelle
quelle
Ich nehme (zu viele?) Wörterbücher:
Wird mit flask (einschließlich jsonify) und flask_sqlalchemy ausgeführt, um Ausgaben als JSON zu drucken.
Rufen Sie die Funktion mit jsonify (serialize ()) auf.
Funktioniert mit allen SQLAlchemy-Abfragen, die ich bisher ausprobiert habe (mit SQLite3)
quelle