2009-07-15 37 views
7

Tôi gặp vấn đề với việc tuần tự hóa các mô hình kế thừa của Django. Ví dụ:Tuần tự hóa Django của mô hình được kế thừa

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

và chỉ mô hình Dog đã được sắp xếp theo thứ tự.

tôi có thể làm smth như

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

Nhưng có vẻ xấu xí và vì mô hình của tôi là rất lớn vì vậy tôi phải sử dụng phân tích cú pháp SAX và với sản lượng như vậy rất khó để phân tích.

Bất kỳ ý tưởng nào về cách tuần tự hóa các mô hình django với lớp cha mẹ?

** CHỈNH SỬA: ** Nó sử dụng để hoạt động ok trước khi áp dụng patch này. Và giải thích tại sao bản vá tồn tại "Mô hình tiết kiệm quá tích cực về việc tạo ra các cá thể lớp cha mới trong quá trình deserialization. Nguyên lưu trên một mô hình bây giờ bỏ qua tiết kiệm của lớp cha mẹ." Tôi nghĩ rằng nên có một tùy chọn để có thể serialize "địa phương trường chỉ "theo mặc định và tùy chọn thứ hai -" tất cả "- để sắp xếp từng trường thừa kế.

+1

Tại sao bạn muốn serialize cái gì đó, cuối cùng, được thiết kế để ánh xạ dữ liệu vào một cơ sở dữ liệu? –

Trả lời

0

Bạn đã xem select_related() chưa? như trong

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

Điều này không hữu ích: 'select_related' không ảnh hưởng đến việc xử lý của django serializer của các mô hình mẹ. – Wogan

+0

'select_related' là một tối ưu hóa. Không có dữ liệu bổ sung được trả về bởi QuerySet. Nó chỉ sử dụng các truy vấn SQL (có khả năng) ít hơn để có được bất kỳ dữ liệu tham chiếu nào. Trong trường hợp trên, không có tham chiếu nào thông qua 'Dog' hoặc' Animal' đến các mô hình khác, vì vậy hoàn toàn không có lợi ích khi sử dụng 'select_related()'. –

1

Bạn tìm thấy câu trả lời trong tài liệu về bản vá.

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

Tuy nhiên, nếu bạn thay đổi Animal là một lớp cơ sở trừu tượng nó sẽ làm việc:

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

    class Meta: 
     abstract = True 

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

này hoạt động như của Django 1.0. Xem http://docs.djangoproject.com/en/dev/topics/db/models/.

1

Bạn sẽ cần một bộ nối tiếp tùy chỉnh để hỗ trợ các trường kế thừa, vì bộ nối tiếp của Django sẽ chỉ tuần tự hóa các trường cục bộ.

tôi đã kết thúc bằng văn bản của riêng tôi khi đối phó với vấn đề này, cảm thấy tự do để sao chép nó: https://github.com/zmathew/django-backbone/blob/master/backbone/serializers.py

Để sử dụng nó trên của riêng mình, bạn cần làm:

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

xin lỗi, liên kết bị hỏng – abrunet

+0

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

0

Bạn có thể xác định một tùy chỉnh serializer:

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

Sử dụng nó như:
serializer = DogSerializer (Dog.objects.all(), nhiều = True) 0.123. in serializer.data enter code here

0

tôi đã cùng một vấn đề, và tôi đã viết một serializer queryset 'nhỏ' đó điều hướng lên cây thừa kế và trả về tất cả các lĩnh vực đăng.

Nó hoàn hảo ...nhưng làm việc cho tôi :)

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

Và đoạn:

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) 
Các vấn đề liên quan