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?

0voto

Han Solo Punkte 1

Ich habe die folgende Funktion verwendet, um das Modell in ein Dictionary zu konvertieren

def model_to_dict(obj):
    return {x: obj.__dict__[x] for x in obj.__dict__ if x in {y.column for y in obj._meta.fields}}

Beispiele

{'id': 8985,
 'title': 'Dmitro',
 'email_address': 'it9+8985@localhost',
 'workspace_id': 'it9',
 'archived': False,
 'deleted': False,
 'inbox': False,
 'read': True,
 'created_at': datetime.datetime(2022, 5, 5, 16, 55, 29, 791844, tzinfo=    ),
 'creator': 'An So',
 'last_message_id': 500566,
 'stat_data': {'count_messages': 1, 'count_attachments': 0},
 'stat_dirty': False,
 'assign_to_id': None,
 'assigned_at': None,
 'assignment_note': None,
 'initial_last_update_ts': 1651769728,
 'renamed_manually': False,
 'unread_timestamp': datetime.datetime(2022, 5, 5, 16, 55, 29, 842507, tzinfo=)}

{'id': 6670,
 'email_id': 473962,
 'message_id': 500620,
 'filename': 'Screenshot.png',
 'size': 6076854,
 'mimetype': 'image/png',
 'aws_key': 'dev/RLpdcza46KFpITDWO_kv_fg2732waccB43z5RmT9/Screenshot.png',
 'aws_key1': '',
 'aws_key_thumb': 'dev/iaCdvcZmUKq-gJim7HT33ID46Ng4WOdxx-TdVuIU/f4b0db49-7f2d-4def-bdc1-8e394f98727f.png',
 's3stored_file_id': 4147}

0voto

Pjl Punkte 1704

Vielleicht hilft dir das. Es konvertiert zwar nicht viele-zu-viele-Beziehungen, aber es ist ziemlich praktisch, wenn du dein Modell im JSON-Format senden möchtest.

def serial_model(modelobj):
  opts = modelobj._meta.fields
  modeldict = model_to_dict(modelobj)
  for m in opts:
    if m.is_relation:
        foreignkey = getattr(modelobj, m.name)
        if foreignkey:
            try:
                modeldict[m.name] = serial_model(foreignkey)
            except:
                pass
  return modeldict

-2voto

sascha Punkte 1

Ich habe einen kleinen Snippet erstellt, der django's model_to_dict verwendet, aber durch die Beziehungen eines Objekts traversiert. Bei zirkulären Abhängigkeiten beendet es die Rekursion und setzt einen String, der auf das abhängige Objekt verweist. Du könntest dies wahrscheinlich erweitern, um nicht bearbeitbare Felder einzuschließen.

Ich benutze es, um Modellsnapshots während des Testens zu erstellen.

from itertools import chain

from django.db.models.fields.files import FileField, ImageField
from django.forms.models import model_to_dict

def get_instance_dict(instance, already_passed=frozenset()):
    """Erstellt eine verschachtelte dict-Version einer Django-Modellinstanz
    Folgt Beziehungen rekursiv, zirkuläre Beziehungen werden beendet, indem
    ein Modell-Identifikator `{model_name}:{instance.id}` gesetzt wird.
    Ignoriert Bild- und Dateifelder."""
    instance_dict = model_to_dict(
        instance,
        fields=[
            f
            for f in instance._meta.concrete_fields
            if not isinstance(f, (ImageField, FileField))
        ],
    )

    already_passed = already_passed.union(
        frozenset((f"{instance.__class__.__name__}:{instance.id}",))
    )
    # Gehe durch mögliche Beziehungen
    for field in chain(instance._meta.related_objects, instance._meta.concrete_fields):
        if (
            (field.one_to_one or field.many_to_one)
            and hasattr(instance, field.name)
            and (relation := getattr(instance, field.name))
        ):
            if (
                model_id := f"{relation.__class__.__name__}:{relation.id}"
            ) in already_passed:
                instance_dict[field.name] = model_id
            else:
                instance_dict[field.name] = get_instance_dict(relation, already_passed)

        if field.one_to_many or field.many_to_many:
            relations = []
            for relation in getattr(instance, field.get_accessor_name()).all():
                if (
                    model_id := f"{relation.__class__.__name__}:{relation.id}"
                ) in already_passed:
                    relations.append(model_id)
                else:
                    relations.append(get_instance_dict(relation, already_passed))
            instance_dict[field.get_accessor_name()] = relations

    return instance_dict

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