代码之家  ›  专栏  ›  技术社区  ›  tefozi

继承模型的django序列化

  •  8
  • tefozi  · 技术社区  · 15 年前

    我对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模型吗?

    **编辑:** patch 已应用。解释为什么补丁存在“模型保存在反序列化过程中创建新的父类实例过于激进。模型上的原始保存现在跳过父类的保存。”我认为应该有一个选项可以在默认情况下序列化“仅本地字段”,第二个选项“all”可以序列化所有继承的字段。

    5 回复  |  直到 7 年前
        1
  •  1
  •   Matt S.    15 年前

    您在修补程序的文档中找到了答案。

    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
  •  1
  •   Zach Mathew    12 年前

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

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

    为了独立使用,您需要:

    serializer = AllFieldsSerializer()
    serializer.serialize(queryset, fields=fields)
    print serializer.getvalue()
    
        3
  •  0
  •   Steven H.    15 年前

    你看过select_related()吗? 如在

    serializers.serialize('xml', Dog.objects.select_related().all())
    
        4
  •  0
  •   Mudit Verma    9 年前

    您可以定义自定义Serializer:

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

    像这样使用它:
    serializer=dogSerializer(dog.objects.all(),many=true)
    打印序列化程序。数据在此处输入代码

        5
  •  0
  •   Agey    7 年前

    我也遇到了同样的问题,我编写了一个'small'queryset序列化器,它在继承树上导航并返回所有序列化的字段。

    这远不是完美的…但对我有效:)

    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)