Сериализация объекта модели в словарь
Как преобразовать объект модели в словарь? Просто для этого в Django есть django.forms.models.model_to_dict
. Вот только у этого варианта есть один существенный недостаток, он не понимает модели привязанные через ForeignKey
и ManyToMany
.
Вообщем вот реализация model_to_dict
которая знает что делать со связанными объектами.
from django.core.exceptions import ObjectDoesNotExist
def model_to_dict(obj, exclude_models=['AutoField', 'ForeignKey', \
'OneToOneField']):
tree = {}
for field_name in obj._meta.get_all_field_names():
try:
field = getattr(obj, field_name)
except ObjectDoesNotExist:
continue
if field.__class__.__name__ in ['RelatedManager', 'ManyRelatedManager']:
if field.model.__name__ in exclude_models:
continue
if field.__class__.__name__ == 'ManyRelatedManager':
exclude_models.append(obj.__class__.__name__)
subtree = []
for related_obj in getattr(obj, field_name).all():
value = model_to_dict(related_obj, \
exclude_models=exclude_models)
if value:
subtree.append(value)
if subtree:
tree[field_name] = subtree
continue
field = obj._meta.get_field_by_name(field_name)[0]
if field.__class__.__name__ in exclude_models:
continue
if field.__class__.__name__ == 'RelatedObject':
exclude_models.append(field.model.__name__)
tree[field_name] = model_to_dict(getattr(obj, field_name), \
exclude_models=exclude_models)
continue
value = getattr(obj, field_name)
if value:
tree[field_name] = value
return tree
Покажу на примере как это работает. Наши модели:
class Author(models.Model):
name = models.CharField(max_length=100)
surname = models.CharField(max_length=100)
birthday = models.DateField(null=True, blank=True)
email = models.EmailField(null=True, blank=True)
def __unicode__(self):
return u'%s %s' % (self.surname, self.name)
class Book(models.Model):
author = models.ManyToManyField(Author, related_name='books')
title = models.CharField(max_length=500)
isdn = models.CharField(max_length=13)
pages = models.IntegerField(null=True, blank=True)
def __unicode__(self):
return u'%s' % self.title
class Review(models.Model):
book = models.ForeignKey(Book, related_name='reviews')
author = models.CharField(max_length=100)
content = models.TextField()
def __unicode__(self):
return u'%s: %s' % (self.author, self.book)
class Rank(models.Model):
review = models.OneToOneField(Review, related_name='rank')
rank = models.IntegerField()
и сообственно как пользоватся:
>>> from models import Book
>>> from utils import model_to_dict
>>> b = Book.objects.get()
>>> model_to_dict(b)
{'reviews': [{'content': u'review text 1', 'rank': {'rank': 5}, 'author': u'author1'}, {'content': u'review text 2', 'author': u'author2'}], 'title': u'Rework: Rework: бизнес без предрассудков', 'pages': 208, 'isdn': u'9785916571196', 'author': [{'surname': u'Фрайд', 'name': u'Джейсон'}, {'surname': u'Хайнемайер', 'name': u'Дэвид'}]}
Вот и все. Все поля что были не заполнены сюда и не попали.