【问题标题】:Django serialization of inherited model继承模型的Django序列化
【发布时间】:2021-11-16 11:25:25
【问题描述】:

我对 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())

并且只有 Dog 模型已被序列化。

我可以做某事

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

但它看起来很丑,因为我的模型很大,所以我必须使用 SAX 解析器,这样的输出很难解析。

知道如何用父类序列化 django 模型吗?

**编辑:** 在应用此 patch 之前它可以正常工作。以及补丁存在的解释“模型保存在反序列化期间创建新的父类实例过于激进。模型上的原始保存现在跳过了父类的保存。”我认为应该有一个选项能够序列化“本地fields only" 默认情况下,第二个选项 - "all" - 序列化所有继承的字段。

【问题讨论】:

  • 为什么要序列化最终设计为将数据映射到数据库的东西?

标签: python django serialization


【解决方案1】:

您在补丁的文档中找到了答案。

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/

【讨论】:

    【解决方案2】:

    您需要一个自定义序列化器来支持继承的字段,因为 Django 的序列化器只会序列化本地字段。

    我在处理这个问题时写了自己的,请随意复制:https://github.com/zmathew/django-backbone/blob/master/backbone/serializers.py

    为了单独使用它,你需要做:

    serializer = AllFieldsSerializer()
    serializer.serialize(queryset, fields=fields)
    print serializer.getvalue()
    
    【解决方案3】:

    我遇到了同样的问题,我编写了一个“小型”查询集序列化程序,它可以向上导航继承树并返回所有序列化的字段。

    它远非完美......但对我有用:)

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

    还有sn-p:

    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)
    

    【讨论】:

      【解决方案4】:

      你可以定义一个自定义的序列化器:

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

      像这样使用它:

      serializer = DogSerializer(Dog.objects.all(), many=True)  
      print serializer.data enter code here
      

      【讨论】:

        【解决方案5】:

        你看过select_related() 吗? 如

        serializers.serialize('xml', Dog.objects.select_related().all())
        

        【讨论】:

        • 这无济于事:select_related 不会影响 django 序列化程序对父模型的处理。
        • select_related 是一种优化。 QuerySet 不会返回额外的数据。它只是使用(可能)更少的 SQL 查询来获取任何引用的数据。在上述情况下,没有通过DogAnimal 对其他模型的引用,因此使用select_related() 绝对没有任何好处。
        猜你喜欢
        • 2011-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-25
        • 2018-12-03
        • 1970-01-01
        • 2019-11-17
        • 1970-01-01
        相关资源
        最近更新 更多