How does one convert a django Model object to a dict with all of its fields? All ideally includes foreign keys and fields with editable=False.
Let me elaborate. Let's say I have a django model like the following:
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")
In the terminal, I have done the following:
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()
I want to convert this to the following dictionary:
{'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}
Questions with unsatisfactory answers:
Django: Converting an entire set of a Model's objects into a single dictionary
How can I turn Django Model objects into a dictionary and still have their foreign keys?
Best Answer
There are many ways to convert an instance to a dictionary, with varying degrees of corner case handling and closeness to the desired result.
1.
instance.__dict__
which returns
This is by far the simplest, but is missing
many_to_many
,foreign_key
is misnamed, and it has two unwanted extra things in it.2.
model_to_dict
which returns
This is the only one with
many_to_many
, but is missing the uneditable fields.3.
model_to_dict(..., fields=...)
which returns
This is strictly worse than the standard
model_to_dict
invocation.4.
query_set.values()
which returns
This is the same output as
instance.__dict__
but without the extra fields.foreign_key_id
is still wrong andmany_to_many
is still missing.5. Custom Function
The code for django's
model_to_dict
had most of the answer. It explicitly removed non-editable fields, so removing that check and getting the ids of foreign keys for many to many fields results in the following code which behaves as desired:While this is the most complicated option, calling
to_dict(instance)
gives us exactly the desired result:6. Use Serializers
Django Rest Framework's ModelSerialzer allows you to build a serializer automatically from a model.
returns
This is almost as good as the custom function, but auto_now_add is a string instead of a datetime object.
Bonus Round: better model printing
If you want a django model that has a better python command-line display, have your models child-class the following:
So, for example, if we define our models as such:
Calling
SomeModel.objects.first()
now gives output like this: