2009-07-15 17 views
7

Ho un problema con la serializzazione dei modelli ereditati da Django. Ad esempioSerializzazione Django del modello ereditato

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

e solo il modello Dog è stato serializzato.

posso fare smth come

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

ma sembra brutto e perché i miei modelli sono molto grandi quindi devo usare SAX parser e con tale uscita è difficile da analizzare.

Qualche idea su come serializzare i modelli django con la classe genitore?

** MODIFICA: ** Funziona correttamente prima che sia stato applicato questo patch. E la spiegazione del perché la patch esiste "Il salvataggio del modello era troppo aggressivo per la creazione di nuove istanze della classe genitore durante la deserializzazione." Salvataggio raw su un modello ora salta il salvataggio della classe genitore. "Penso che ci dovrebbe essere un'opzione per poter serializzare" locale solo campi "per impostazione predefinita e seconda opzione -" tutto "- per serializzare tutti i campi ereditati.

+1

Perché vuoi serializzare qualcosa che è, alla fine, progettato per mappare i dati in un database? –

risposta

0

Hai guardato select_related()? come in

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

Questo non aiuta: 'select_related' non influenza la gestione del serializzatore di django dei modelli principali. – Wogan

+0

'select_related' è un'ottimizzazione. Nessun dato aggiuntivo viene restituito da QuerySet. Utilizza solo (potenzialmente) meno query SQL per ottenere dati di riferimento. Nel caso precedente, non ci sono riferimenti attraverso "Cane" o "Animale" ad altri modelli, quindi non c'è assolutamente alcun vantaggio nell'usare 'select_related()'. –

1

Hai trovato la tua risposta nella documentazione della patch.

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

Tuttavia, se si cambia Animal di essere una classe base astratta che funzionerà:

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

    class Meta: 
     abstract = True 

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

Questo funziona come di Django 1.0. Vedi http://docs.djangoproject.com/en/dev/topics/db/models/.

1

Avrete bisogno di un serializzatore personalizzato per supportare i campi ereditati, poiché il serializzatore di Django serializzerà solo i campi locali.

ho finito per scrivere la mia quando si tratta di questo problema, sentitevi liberi di copiarlo: https://github.com/zmathew/django-backbone/blob/master/backbone/serializers.py

Al fine di utilizzarlo da solo, è necessario fare:

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

scusate, collegamento interrotto – abrunet

+0

https://github.com/zmathew/django-backbone/blob/351fc75797bc3c75d2aa5c582089eb39ebb6f19a/backbone/serializers.py – test30

0

Puoi definire un serializzatore personalizzato:

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

utilizzarlo come:
serializer = DogSerializer (Dog.objects.all(), molti = true) 0.123. stampa serializer.data inserire il codice qui

0

Ho avuto lo stesso problema e ho scritto un 'piccolo' serializzatore set di query, che naviga l'albero di ereditarietà e restituisce tutti i campi serializzati.

È tutt'altro che perfetto ...ma funziona per me :)

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

E il frammento:

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) 
Problemi correlati