2009-07-15 106 views
7

我有一個Django繼承模型序列化的問題。例如,繼承模型的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已被應用之前,它用於正常工作。並解釋爲什麼該補丁存在「模型保存對於在反序列化過程中創建新的父類實例過於激進。原型保存模型現在跳過保存父類。」我認爲應該有一個選項能夠序列化「本地字段「,第二個選項 - 」全部「 - 序列化所有繼承的字段。

+1

你爲什麼要序列化的東西是,在最後,旨在將數據映射到數據庫? – 2009-07-15 21:26:33

回答

0

你看過select_related()嗎? 與

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

這沒有幫助:`select_related`不影響django序列化程序對父模型的處理。 – Wogan 2009-07-29 02:39:50

+0

`select_related`是一個優化。 QuerySet不返回額外的數據。它只是使用(可能)更少的SQL查詢來獲取任何引用的數據。 在上面的例子中,沒有通過`Dog`或`Animal`來引用其他模型,所以使用`select_related()`絕對沒有任何好處。 – 2009-08-21 16:37:40

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/

1

你需要一個自定義序列化器來支持繼承字段,因爲Django的序列化器只會序列化本地字段。

我結束了處理這個問題的時候寫我自己的,隨意複製:https://github.com/zmathew/django-backbone/blob/master/backbone/serializers.py

爲了使用它自己的,你需要做的:

serializer = AllFieldsSerializer() 
serializer.serialize(queryset, fields=fields) 
print serializer.getvalue() 
0

你可以定義自定義序列:

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

使用方法如下:
串行= DogSerializer(Dog.objects.all(),多=真)
print serializer.data在這裏輸入代碼

0

我有同樣的問題,我寫了一個'小'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)