Wie konvertiert man ein Django-Modellobjekt in ein Diktat mit all seinen Feldern? Alles beinhaltet idealerweise Fremdschlüssel und Felder mit editable=False
.
Lassen Sie mich näher darauf eingehen. Angenommen, ich habe ein Django-Modell wie das folgende:
from django.db import models
class OtherModel(models.Model): pass
class SomeModel(models.Model):
normal_value = models.IntegerField()
readonly_value = models.IntegerField(editable=False)
auto_now_add = models.DateTimeField(auto_now_add=True)
foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")
Im Terminal habe ich Folgendes getan:
other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()
Ich möchte dies in das folgende Wörterbuch konvertieren:
{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
'foreign_key': 1,
'id': 1,
'many_to_many': [1],
'normal_value': 1,
'readonly_value': 2}
Fragen mit unbefriedigenden Antworten:
Django: Konvertieren eines ganzen Satzes von Objektobjekten in ein einziges Wörterbuch
to_dict
und wie gewünscht behandeln._meta
Definitionen des Modells durchgesehen , um die mit dem Modell verknüpften Felder zu finden und ihre Werte für die Instanz abzurufen.Antworten:
Es gibt viele Möglichkeiten, eine Instanz in ein Wörterbuch zu konvertieren, mit unterschiedlichem Grad an Behandlung von Eckfällen und Nähe zum gewünschten Ergebnis.
1.
instance.__dict__
was zurückkehrt
Dies ist bei weitem das einfachste, fehlt aber
many_to_many
,foreign_key
ist falsch benannt und enthält zwei unerwünschte zusätzliche Dinge.2.
model_to_dict
was zurückkehrt
Dies ist die einzige mit
many_to_many
, aber es fehlen die nicht bearbeitbaren Felder.3.
model_to_dict(..., fields=...)
was zurückkehrt
Dies ist streng schlechter als der Standardaufruf
model_to_dict
.4.
query_set.values()
was zurückkehrt
Dies ist die gleiche Ausgabe wie,
instance.__dict__
jedoch ohne die zusätzlichen Felder.foreign_key_id
ist immer noch falsch undmany_to_many
fehlt immer noch.5. Benutzerdefinierte Funktion
Der Code für Djangos
model_to_dict
hatte die meiste Antwort. Nicht bearbeitbare Felder wurden explizit entfernt. Wenn Sie diese Prüfung entfernen und die IDs von Fremdschlüsseln für viele bis viele Felder abrufen, erhalten Sie den folgenden Code, der sich wie gewünscht verhält:Während dies die komplizierteste Option ist,
to_dict(instance)
liefert der Anruf genau das gewünschte Ergebnis:6. Verwenden Sie Serializer
Mit dem ModelSerialzer von Django Rest Framework können Sie einen Serializer automatisch aus einem Modell erstellen.
kehrt zurück
Dies ist fast so gut wie die benutzerdefinierte Funktion, aber auto_now_add ist eine Zeichenfolge anstelle eines datetime-Objekts.
Bonusrunde: Besserer Modelldruck
Wenn Sie ein Django-Modell mit einer besseren Python-Befehlszeilenanzeige möchten, lassen Sie Ihre Modelle wie folgt untergeordnet sein:
Wenn wir zum Beispiel unsere Modelle als solche definieren:
Wenn Sie
SomeModel.objects.first()
jetzt anrufen, erhalten Sie folgende Ausgabe:quelle
isinstance
Test in Lösung 5 (und den Bonus) in ändernif f.many_to_many
.model_to_dict
Code modelliert , der verwendetisinstance
. Ich bin nicht sicher, warum sie diese Wahl getroffen haben, aber es kann einen guten Grund dafür geben (wie diemany_to_many
Eigenschaft, die in einer späteren Version eingeführt wird)@property
Felder zurückgeben?Ich habe eine gute Lösung gefunden, um zum Ergebnis zu gelangen:
Angenommen, Sie haben ein Modellobjekt
o
:Ruf einfach an:
quelle
@ Zags Lösung war wunderschön!
Ich würde jedoch eine Bedingung für Datumsfelder hinzufügen, um es JSON-freundlich zu machen.
Bonusrunde
Wenn Sie ein Django-Modell mit einer besseren Python-Befehlszeilenanzeige möchten, lassen Sie die untergeordnete Klasse Ihres Modells wie folgt lauten:
Wenn wir zum Beispiel unsere Modelle als solche definieren:
Wenn Sie
SomeModel.objects.first()
jetzt anrufen, erhalten Sie folgende Ausgabe:quelle
Einfachster Weg,
Wenn Ihre Abfrage Model.Objects.get () lautet:
get () gibt eine einzelne Instanz zurück, damit Sie sie direkt
__dict__
von Ihrer Instanz aus verwenden könnenmodel_dict =
Model.Objects.get().__dict__
für filter () / all ():
all () / filter () gibt eine Liste der Instanzen zurück, damit Sie
values()
eine Liste der Objekte abrufen können.model_values = Model.Objects.all (). values ()
quelle
nur
vars(obj)
wird sie die ganzen Werte des Objekts angebenSie können dies auch hinzufügen
quelle
Aktualisieren
Die neuere aggregierte Antwort von @zags ist vollständiger und eleganter als meine eigene. Bitte beziehen Sie sich stattdessen auf diese Antwort.
Original
Wenn Sie bereit sind, Ihre eigene to_dict-Methode zu definieren, wie von @karthiker vorgeschlagen, führt dies dieses Problem nur zu einem Mengenproblem.
Wir müssen die falsch beschrifteten Fremdschlüssel aus otherDict entfernen .
Zu diesem Zweck können wir eine Schleife verwenden, die ein neues Wörterbuch erstellt, das alle Elemente außer denen mit Unterstrichen enthält. Um Zeit zu sparen, können wir diese einfach zum ursprünglichen Diktat hinzufügen, da Wörterbücher nur unter der Haube gespeichert werden.
Somit bleibt uns das folgende Diktat :
Und das gibst du einfach zurück.
Auf der anderen Seite können Sie keine Unterstriche in Ihren bearbeitbaren = falschen Feldnamen verwenden. Auf der anderen Seite funktioniert dies für alle Felder, in denen die vom Benutzer erstellten Felder keine Unterstriche enthalten.
Dies ist nicht der beste Weg, dies zu tun, aber es könnte als vorübergehende Lösung funktionieren, bis eine direktere Methode gefunden wird.
Für das folgende Beispiel würde dict basierend auf model_to_dict gebildet und otherDict würde durch die Filterwertmethode gebildet. Ich hätte dies mit den Modellen selbst gemacht, aber ich kann meine Maschine nicht dazu bringen, andere Modelle zu akzeptieren.
Das sollte Sie in einen groben Ballpark der Antwort auf Ihre Frage bringen, hoffe ich.
quelle
re
möchten. Wenn Schlüssel mit Unterstrichen herausgefiltert werden sollen, ist dies weder korrekter Code noch korrektes Verhalten.re.match("_", "reference1_id")
RückgabenNone
und legitime Spalten in der Datenbank enthalten möglicherweise Unterstriche in ihren Namen.editable=false
Bereichen tun würden . Ich habe nur versucht, etwas bereitzustellen, mit dem Sie möglicherweise arbeiten können, bis eine kanonischere Lösung geliefert werden kann."_" in string
eher alsre
in diesem Fall verwenden.in
anstelle von zu verwendenre
.Viele interessante Lösungen hier. Meine Lösung bestand darin, meinem Modell eine as_dict-Methode mit einem Diktatverständnis hinzuzufügen.
Als Bonus bietet diese Lösung in Kombination mit einem Listenverständnis über eine Abfrage eine gute Lösung, wenn Sie Ihre Modelle in eine andere Bibliothek exportieren möchten. Beispiel: Speichern Sie Ihre Modelle in einem Pandas-Datenrahmen:
quelle
(wollte den Kommentar nicht machen)
Ok, es hängt nicht wirklich von den Typen auf diese Weise ab. Möglicherweise habe ich die ursprüngliche Frage hier falsch verstanden. Verzeihen Sie mir, wenn dies der Fall ist. Wenn Sie serliazers.py erstellen, erstellen Sie dort Klassen mit Metaklassen.
Wenn Sie dann die Daten in der Ansichtsklasse erhalten, können Sie:
Das ist so ziemlich das, was ich an verschiedenen Orten habe und es gibt über den JSONRenderer einen schönen JSON zurück.
Wie gesagt, dies ist mit freundlicher Genehmigung von DjangoRestFramework, daher lohnt es sich, dies zu untersuchen.
quelle
Der einfachere Weg ist, einfach zu verwenden
pprint
, was in Basis-Python istDies ergibt eine Ausgabe, die ähnlich aussieht,
json.dumps(..., indent = 4)
aber die seltsamen Datentypen, die möglicherweise in Ihre Modellinstanz eingebettet sind, wie z. B.ModelState
undUUID
usw., korrekt verarbeitet .Getestet auf Python 3.7
quelle
Vielleicht hilft dir das. Möge dies nicht viele bis viele Beziehungen verbergen, aber es ist ziemlich praktisch, wenn Sie Ihr Modell im JSON-Format senden möchten.
quelle
Beste Lösung, die Sie je gesehen haben.
Konvertieren Sie die Instanz django.db.models.Model und alle zugehörigen Funktionsfelder ForeignKey, ManyToManyField und @Property in dict.
https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52
quelle
Die Antwort von @zags ist umfassend und sollte ausreichen,
aber dieMethodeNr. 5(die beste IMO) gibt einen Fehler aus, sodass ich dieHilfsfunktionverbessert habe.Da das OP die Konvertierung von
many_to_many
Feldern in eine Liste von Primärschlüsseln anstelle einer Liste von Objekten anforderte , habe ich die Funktion erweitert, sodass der Rückgabewert jetzt JSON-serialisierbar ist - indemdatetime
Objekte instr
undmany_to_many
Objekte in eine Liste von IDs konvertiert werden .quelle
concrete_fields
undm2m_fields
sieht identisch aus. Angenommen, diem2m_fields
Schleife ist hier falsch implementiert.AttributeError: 'list' object has no attribute 'values_list'
dass ich den Grund dafür nicht finden konnte.field.value_from_object
und infolgedessen von geändertmodel_to_dict
. Ich habe Abschnitt 5 meiner Antwort aktualisiert, um dies widerzuspiegeln.