466 Stimmen

Konvertiere ein Django-Modellobjekt in ein Dictionary mit allen Feldern intakt

Wie konvertiert man ein Django-Model-Objekt in ein Dict mit allen seinen Feldern? Alle sollten idealerweise auch Fremdschlüssel und Felder mit editable=False enthalten.

Lassen Sie mich das genauer erklären. Angenommen, ich habe ein Django-Modell wie folgt:

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 gemacht:

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 Dictionary konvertieren:

{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=),
 'foreign_key': 1,
 'id': 1,
 'many_to_many': [1],
 'normal_value': 1,
 'readonly_value': 2}

Fragen mit unbefriedigenden Antworten:

Django: Konvertierung eines gesamten Sets von Objekten eines Modells in ein einziges Dictionary

Wie kann ich Django-Model-Objekte in ein Dictionary umwandeln und immer noch ihre Fremdschlüssel behalten?

8voto

dfcoelho Punkte 109

Die Lösung von @Zags war wunderschön!

Ich würde jedoch eine Bedingung für Datum-Felder hinzufügen, um sie JSON-freundlich zu machen.

Bonus Runde

Wenn Sie ein Django-Modell möchten, das eine bessere pythonische Befehlszeilenanzeige hat, lassen Sie Ihre Modelle das folgende Unterklassen:

from django.db import models
from django.db.models.fields.related import ManyToManyField

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self):
        opts = self._meta
        data = {}
        for f in opts.concrete_fields + opts.many_to_many:
            if isinstance(f, ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = list(f.value_from_object(self).values_list('pk', flat=True))
            elif isinstance(f, DateTimeField):
                if f.value_from_object(self) is not None:
                    data[f.name] = f.value_from_object(self).timestamp()
            else:
                data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)
        return data

    class Meta:
        abstract = True

Also, wenn wir unsere Modelle zum Beispiel folgendermaßen definieren:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    value = models.IntegerField()
    value2 = models.IntegerField(editable=False)
    created = models.DateTimeField(auto_now_add=True)
    reference1 = models.ForeignKey(OtherModel, related_name="ref1")
    reference2 = models.ManyToManyField(OtherModel, related_name="ref2")

Der Aufruf von SomeModel.objects.first() gibt jetzt eine Ausgabe wie diese:

{'created': 1426552454.926738,
'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]}

5voto

Enock Simiyu Punkte 180

Ich bin auf dieses Problem gestoßen, als ich versuchte, eine Django-Website in eine API unter Verwendung des Django-Rest-Frameworks umzuwandeln. Normalerweise gibt Django drei Arten von Objekten aus der Datenbank zurück. Dazu gehören ein Queryset, eine Modelinstanz und ein Paginator-Objekt. In meinem Fall waren dies diejenigen, die umgewandelt werden mussten.

Queryset

Ein Queryset ist wie eine Liste von Modellobjekten in Django. Hier ist der Code, um es in ein Dictionary umzuwandeln.

model_data=Model.object.all()# Dies gibt ein Queryset-Objekt zurück
model_to_dict=[model for model in model_data.values()]
return Response(model_to_dict,status=status.HTTP_200_OK)

Model-Instanz

Ein Modellobjekt ist ein einzelnes Objekt eines Modells.

model_instance=Model.objects.get(pk=1)# Dies gibt nur ein einzelnes Modellobjekt zurück
model_to_dict=model_to_dict(model_instance)
return Response(model_to_dict,status=status.HTTP_200_OK)

Paginator-Objekt

Ein Paginator-Objekt ist ein Objekt, das Modellobjekte einer bestimmten Seite enthält.

model_queryset=Model.objects.all()
paginator = Paginator(model_queryset, 10)
try:
    selected_results = paginator.page(page)
except Exception:
    selected_results=result
paginator_to_dict=list(selected_results.object_list.values())
return Response(selected_results,status=status.HTTP_200_OK)

Zumindest so habe ich es gelöst.

5voto

user5359531 Punkte 2950

Der einfachere Weg ist es, einfach pprint zu verwenden, das in Basis-Python vorhanden ist

import pprint
item = MyDjangoModel.objects.get(name = 'foo')
pprint.pprint(item.__dict__, indent = 4)

Dies gibt eine Ausgabe, die ähnlich aussieht wie json.dumps(..., indent = 4), aber es behandelt korrekt die seltsamen Datentypen, die in Ihrer Model-Instanz eingebettet sein könnten, wie ModelState und UUID usw.

Getestet auf Python 3.7

2voto

nathj07 Punkte 645

(habe nicht beabsichtigt, den Kommentar zu machen)

Ok, es hängt nicht wirklich auf diese Weise von Typen ab. Ich habe die ursprüngliche Frage vielleicht falsch verstanden, also verzeihen Sie mir, wenn das der Fall ist. Wenn Sie serliazers.py erstellen, dann erstellen Sie dort Klassen, die Meta-Klassen haben.

Klasse MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = modelName
        fields =('csv','von','Felder')

Dann, wenn Sie die Daten in der Ansichtsklasse erhalten, können Sie folgendes tun:

model_data - Model.objects.filter(...)
serializer = MyModelSerializer(model_data, many=True)
return Response({'data': serilaizer.data}, status=status.HTTP_200_OK)

Das ist so ziemlich das, was ich an verschiedenen Stellen habe und es liefert schönes JSON über den JSONRenderer zurück.

Wie gesagt, das kommt von DjangoRestFramework, also ist es sinnvoll, sich das anzusehen.

2voto

t1m0 Punkte 715

Viele interessante Lösungen hier. Meine Lösung bestand darin, meiner Modellklasse eine as_dict-Methode mit einer dict comprehension hinzuzufügen.

def as_dict(self):
    return dict((f.name, getattr(self, f.name)) for f in self._meta.fields)

Als Bonus ergibt diese Lösung in Kombination mit einer Listen-Comprehension über eine Abfrage eine gute Lösung, wenn Sie Ihre Modelle in eine andere Bibliothek exportieren möchten. Zum Beispiel, indem Sie Ihre Modelle in ein pandas DataFrame ablegen:

pandas_awesomeness = pd.DataFrame([m.as_dict() for m in SomeModel.objects.all()])

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X