Сериализация объекта модели в словарь

Как преобразовать объект модели в словарь? Просто для этого в 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'Дэвид'}]}

Вот и все. Все поля что были не заполнены сюда и не попали.