[Django]-How can I turn Django Model objects into a dictionary and still have their foreign keys?

32👍

obj = get_object_or_404(CustomModel,id=some_id)
my_dict = obj.__dict__

8👍

How about:

model_to_dict(instance, fields=[field.name for field in instance._meta.fields])

By explicitly naming all of the fields, it should give you the foreign key ids at least (although I haven’t verified).

Note that this function does not return fields with editable=False (since it is intended for forms).

👤Chad

8👍

I think I had the same need as you — I wanted a plain-and-simple dict representation of an object. the other answers posted (at the time I write) wouldn’t give me that, and the serializers, while useful for their purpose, produce output with extra info I don’t want, and an inconvenient structure.

Though admittedly a hack, this is giving me good mileage:

from django.core import serializers

def obj_to_dict(model_instance):
    serial_obj = serializers.serialize('json', [model_instance])
    obj_as_dict = json.loads(serial_obj)[0]['fields']
    obj_as_dict['pk'] = model_instance.pk
    return obj_as_dict

wrapping the django_model_object in a list, then accessing item 0 after parsing the json is needed because, for some reason, serializers can only serialize iterables of model objects (weird).

You’d need some extra gears to handle any kind of foreign key fields, I may post back if I end up needing to write that (unless someone else edits it in first!).

HTH for now.

0👍

You may want to have look at Django serialization if you want to work with related models.

👤Rohan

0👍

None of the other answers quite worked for me. This, however, seemed to do the trick.

def model_to_dict(instance, include=None, exclude=None):
    fields = instance._meta.concrete_fields
    if include is not None:
        return {f.attname: getattr(instance, f.attname) for f in fields if f.name in include}
    if exclude is not None:
        return {f.attname: getattr(instance, f.attname) for f in fields if f.name not in exclude}
    return {f.attname: getattr(instance, f.attname) for f in fields}

0👍

I imagine that you’ve already solved this problem for your case, but I found some info as I was searching for similar solutions. I wanted to be able to access objects and their fields/attributes in a template. I am just learning django.

What I finally read-up on was the https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-display/, which seem to be able to send an object instance or a queryset of objects along to a template. Then you can access the objects like the model.field, or even if it’s a foreignkey field, model.foreignmodel.foreignmodelfield.

So it’s been pretty useful for me. This was after I built a bunch of custom ‘to-dict’ methods in different class managers. This helped me a lot. But you’ll have to read up on the Generic Views and how to customize them to really get the details you want.

-Matt

Leave a comment