Джанго сериализация наследственной модели - PullRequest
8 голосов
/ 15 июля 2009

У меня проблема с сериализацией унаследованных моделей Django. Например

class Animal(models.Model):
    color = models.CharField(max_length=50)

class Dog(Animal):
    name = models.CharField(max_length=50)

...
# now I want to serialize Dog model with Animal inherited fields obviously included
print serializers.serialize('xml', Dog.objects.all())

и только модель собаки была сериализована.

Я могу сделать что-то вроде

all_objects = list(Animal.objects.all()) + list(Dog.objects.all())
print serializers.serialize('xml', all_objects)

Но это выглядит некрасиво, и потому что мои модели очень большие, поэтому я должен использовать SAX-парсер, и с таким выводом трудно разобрать.

Есть идеи, как сериализовать модели django с родительским классом?

** РЕДАКТИРОВАТЬ: ** Он работал нормально до того, как патч был применен. И объяснение, почему существует патч: «Сохранение модели было слишком агрессивным по отношению к созданию новых экземпляров родительского класса во время десериализации. Теперь при непосредственном сохранении модели пропускается сохранение родительского класса. только поля «по умолчанию» и вторая опция - «все» - для сериализации всех унаследованных полей.

Ответы [ 5 ]

1 голос
/ 20 августа 2009

Вы нашли свой ответ в документации к патчу.

all_objects = list(Animal.objects.all()) + list(Dog.objects.all())
print serializers.serialize('xml', all_objects)

Однако, если вы измените Animal на абстрактный базовый класс, он будет работать:

class Animal(models.Model):
    color = models.CharField(max_length=50)

    class Meta:
        abstract = True

class Dog(Animal):
    name = models.CharField(max_length=50)

Это работает с Django 1.0. Смотри http://docs.djangoproject.com/en/dev/topics/db/models/.

1 голос
/ 07 февраля 2013

Вам потребуется специальный сериализатор для поддержки унаследованных полей, поскольку сериализатор Django будет сериализовать только локальные поля.

Я написал свою собственную статью, когда решал эту проблему, не стесняйтесь ее копировать: https://github.com/zmathew/django-backbone/blob/master/backbone/serializers.py

Для того, чтобы использовать его самостоятельно, вам нужно сделать:

serializer = AllFieldsSerializer()
serializer.serialize(queryset, fields=fields)
print serializer.getvalue()
0 голосов
/ 13 апреля 2017

У меня была такая же проблема, и я написал «маленький» сериализатор наборов запросов, который перемещается вверх по дереву наследования и возвращает все поля сериализации.

Это далеко не идеально ... но у меня работает :) 1003 *

a = QuerySetSerializer(MyModel, myqueryset)
a.serialize()

И фрагмент:

from __future__ import unicode_literals
import json
import inspect
from django.core import serializers
from django.db.models.base import Model as DjangoBaseModel
class QuerySetSerializer(object):
    def __init__(self, model, initial_queryset):
        """
        @param model: The model of your queryset
        @param initial_queryset: The queryset to serialize
        """
        self.model = model
        self.initial_queryset = initial_queryset
        self.inheritance_tree = self._discover_inheritance_tree()

    def serialize(self):
        list_of_querysets = self._join_inheritance_tree_objects()
        merged_querysets = self._zip_queryset_list(list_of_querysets)

        result = []
        for related_objects in merged_querysets:
            result.append(self._serialize_related_objects(related_objects))
        return json.dumps(result)

    def _serialize_related_objects(self, related_objects):
        """
        In this method, we serialize each instance using the django's serializer function as shown in :
        See https://docs.djangoproject.com/en/1.10/topics/serialization/#inherited-models

        However, it returns a list with mixed objects... Here we join those related objects into one single dict
        """
        serialized_objects = []

        for related_object in related_objects:
            serialized_object = self._serialize_object(related_object)
            fields = serialized_object['fields']
            fields['pk'] = serialized_object['pk']
            serialized_objects.append(fields)

        merged_related_objects = {k: v for d in serialized_objects for k, v in d.items()}
        return merged_related_objects

    def _serialize_object(self, obj):
        data = serializers.serialize('json', [obj, ])
        struct = json.loads(data)
        return struct[0]

    def _discover_inheritance_tree(self):
        # We need to find the inheritance tree which excludes abstract classes,
        # so we can then join them when serializing the instance
        return [x for x in inspect.getmro(self.model) if x is not object and x is not DjangoBaseModel and not x._meta.abstract]

    def _join_inheritance_tree_objects(self):
        """
        Here we join the required querysets from the non abstract inherited models, which we need so we are able to
        serialize them.

        Lets say that MyUser inherits from Customer and customer inherits from django's User model
        This will return [list(MyUser.objects.filter(...), list(Customer.objects.filter(...), list(User.objects.filter(...)
        """

        initial_ids = self._get_initial_ids()
        inheritance__querysets = [list(x.objects.filter(id__in=initial_ids).order_by("id")) for x in self.inheritance_tree]
        return inheritance__querysets

    def _zip_queryset_list(self, list_of_querysets):
        """
        At this stage, we have something like:
        (
            [MyUser1, MyUser2, MyUser3],
            [Customer1, Customer2, Customer3],
            [User1, User2, User3]
        )

        And to make it easier to work with, we 'zip' the list of lists so it looks like:
        (
            [MyUser1, Customer1, User1],
            [MyUser2, Customer2, User2],
            [MyUser3, Customer3, User3],
        )

        """
        return zip(*list_of_querysets)

    def _get_initial_ids(self):
        """
        Returns a list of ids of the initial queryset
        """
        return self.initial_queryset.order_by("id").values_list("id", flat=True)
0 голосов
/ 22 августа 2015

Вы можете определить пользовательский сериализатор:

class DogSerializer(serializers.ModelSerializer):  
    class Meta:  
       model = Dog 
        fields = ('color','name') 

Используйте это как:
serializer = DogSerializer (Dog.objects.all (), многие = True)
напечатайте serializer.data введите код здесь

0 голосов
/ 24 июля 2009

Вы смотрели на select_related ()? как в

serializers.serialize('xml', Dog.objects.select_related().all())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...