2010-04-06 74 views
15

在序列化Django模型類時,有沒有辦法將任何@property定義傳遞給json序列化程序?在Python類中序列化@property方法

例如:

class FooBar(object.Model) 

    name = models.CharField(...) 

    @property 
    def foo(self): 
     return "My name is %s" %self.name 

要序列化到:

def list_class_properties(cls): 
    return [k for k,v in cls.__dict__.iteritems() if type(v) is property] 

例如:

[{ 

    'name' : 'Test User', 

    'foo' : 'My name is Test User', 
},] 

回答

0

你可以使用一些魔法讓所有類的屬性:

>>> class Foo: 
     @property 
     def bar(self): 
      return "bar" 

>>> list_class_properties(Foo) 
['bar'] 

然後你可以建立字典並從那裏序列化它。

+0

這需要基本創造我自己的哈希,只連載基本上哈希。如果我走這條路線,我幾乎可以切斷整個系列化。 我一直希望繼續使用django Model類,並簡單地調用serialize('json',my_object,...) – ashchristopher 2010-04-07 03:29:36

+0

不幸的是,似乎Django的核心序列化例程明確排除了不在_meta中的任何東西基本上只查找數據庫模型字段。所以,雖然你可以寫出一個功能,只拉出屬性字段(這可能會更好地完成「檢查」。getmembers'方法在第二次腮紅時),即使使用'serializers.serialize'方法的'fields'參數也不起作用。 看到這裏,他們在迭代傳入的查詢集,只查找'_meta'中的內容:http://code.djangoproject.com/browser/django/trunk/django/core/serializers/base.py# L39 – 2010-04-07 14:55:09

12

您可以擴展Django的序列化程序,而不需要做太多的工作。這是一個自定義序列化程序,它接受查詢集和屬性列表(不是字段),並返回JSON。

from StringIO import StringIO 
from django.core.serializers.json import Serializer 

class MySerializer(Serializer): 
    def serialize(self, queryset, list_of_attributes, **options): 
     self.options = options 
     self.stream = options.get("stream", StringIO()) 
     self.start_serialization() 
     for obj in queryset: 
      self.start_object(obj) 
      for field in list_of_attributes: 
       self.handle_field(obj, field) 
      self.end_object(obj) 
     self.end_serialization() 
     return self.getvalue() 

    def handle_field(self, obj, field): 
     self._current[field] = getattr(obj, field) 

用法:

>>> MySerializer().serialize(MyModel.objects.all(), ["field1", "property2", ...]) 

當然,這不只是寫自己的簡單的JSON序列可能更多的工作,但也許比你自己的XML序列化沒有更多的工作(你必須重新定義「handle_field」除了更改基類以外,還匹配XML案例)。

+0

在Django(1.5.4)上獲取''MySerializer'對象沒有屬性'first''錯誤 – 2013-11-18 10:43:24

5

事情自2010年以來有所改變,所以@ user85461的答案似乎不再適用於Django 1.8和Python 3.4。這是一個更新的答案,似乎對我有用。

from django.core.serializers.base import Serializer as BaseSerializer 
from django.core.serializers.python import Serializer as PythonSerializer 
from django.core.serializers.json import Serializer as JsonSerializer 
from django.utils import six 

class ExtBaseSerializer(BaseSerializer): 
    """ Abstract serializer class; everything is the same as Django's base except from the marked lines """ 
    def serialize(self, queryset, **options): 
     self.options = options 

     self.stream = options.pop('stream', six.StringIO()) 
     self.selected_fields = options.pop('fields', None) 
     self.selected_props = options.pop('props', None) # added this 
     self.use_natural_keys = options.pop('use_natural_keys', False) 
     self.use_natural_foreign_keys = options.pop('use_natural_foreign_keys', False) 
     self.use_natural_primary_keys = options.pop('use_natural_primary_keys', False) 

     self.start_serialization() 
     self.first = True 
     for obj in queryset: 
      self.start_object(obj) 
      concrete_model = obj._meta.concrete_model 
      for field in concrete_model._meta.local_fields: 
       if field.serialize: 
        if field.rel is None: 
         if self.selected_fields is None or field.attname in self.selected_fields: 
          self.handle_field(obj, field) 
        else: 
         if self.selected_fields is None or field.attname[:-3] in self.selected_fields: 
          self.handle_fk_field(obj, field) 
      for field in concrete_model._meta.many_to_many: 
       if field.serialize: 
        if self.selected_fields is None or field.attname in self.selected_fields: 
         self.handle_m2m_field(obj, field) 
      # added this loop 
      if self.selected_props: 
       for field in self.selected_props: 
        self.handle_prop(obj, field) 
      self.end_object(obj) 
      if self.first: 
       self.first = False 
     self.end_serialization() 
     return self.getvalue() 

    # added this function 
    def handle_prop(self, obj, field): 
     self._current[field] = getattr(obj, field) 


class ExtPythonSerializer(ExtBaseSerializer, PythonSerializer): 
    pass 


class ExtJsonSerializer(ExtPythonSerializer, JsonSerializer): 
    pass 

用法:

>>> ExtJsonSerializer().serialize(MyModel.objects.all(), fields=['myfield', ...], props=['myprop', ...]) 
+2

這是正確的答案,對我很好。 – Rafay 2015-12-23 13:48:58

+0

發佈了一個改進版本。 – caot 2016-07-07 19:09:08

3

該解決方案行之有效由M. Rafay阿利姆和Wtower提出,但它的重複大量的代碼。下面是一個改良效果:

from django.core.serializers.base import Serializer as BaseSerializer 
from django.core.serializers.python import Serializer as PythonSerializer 
from django.core.serializers.json import Serializer as JsonSerializer 

class ExtBaseSerializer(BaseSerializer): 

    def serialize_property(self, obj): 
     model = type(obj) 
     for field in self.selected_fields: 
      if hasattr(model, field) and type(getattr(model, field)) == property: 
       self.handle_prop(obj, field) 

    def handle_prop(self, obj, field): 
     self._current[field] = getattr(obj, field) 

    def end_object(self, obj): 
     self.serialize_property(obj) 

     super(ExtBaseSerializer, self).end_object(obj) 


class ExtPythonSerializer(ExtBaseSerializer, PythonSerializer): 
    pass 


class ExtJsonSerializer(ExtPythonSerializer, JsonSerializer): 
    pass 

如何使用它:

ExtJsonSerializer().serialize(MyModel.objects.all(), fields=['field_name_1', 'property_1' ...]) 
1

這是M. Rafay阿利姆和Wtowers答案,caots的組合。 這是DRY,並且只允許您指定額外的道具,而不是像caots版本中的所有字段和道具。

from django.core.serializers.json import Serializer as JsonSerializer 
from django.core.serializers.python import Serializer as PythonSerializer 
from django.core.serializers.base import Serializer as BaseSerializer 

class ExtBaseSerializer(BaseSerializer): 
    def serialize(self, queryset, **options): 
     self.selected_props = options.pop('props') 
     return super(ExtBaseSerializer, self).serialize(queryset, **options) 

    def serialize_property(self, obj): 
     model = type(obj) 
     for field in self.selected_props: 
      if hasattr(model, field) and type(getattr(model, field)) == property: 
       self.handle_prop(obj, field) 

    def handle_prop(self, obj, field): 
     self._current[field] = getattr(obj, field) 

    def end_object(self, obj): 
     self.serialize_property(obj) 

     super(ExtBaseSerializer, self).end_object(obj) 

class ExtPythonSerializer(ExtBaseSerializer, PythonSerializer): 
    pass 

class ExtJsonSerializer(ExtPythonSerializer, JsonSerializer): 
    pass 

如何使用它:

ExtJsonSerializer().serialize(MyModel.objects.all(), props=['property_1', ...])