序列化Python类中的@property方法

24 投票
5 回答
10694 浏览
提问于 2025-04-15 21:18

有没有办法让Django模型类中的任何@property定义在进行JSON序列化时被传递给JSON序列化器呢?

举个例子:

class FooBar(object.Model)

    name = models.CharField(...)

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

想要序列化成:

[{

    'name' : 'Test User',

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

5 个回答

7

这是M. Rafay Aleem、Wtowers和caots的答案结合在一起的内容。这个方法遵循了“不要重复自己”的原则,让你只需要指定额外的属性,而不是像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', ...])
7

由M. Rafay Aleem和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' ...])
13

你可以在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的情况,并且还要更改基类来实现这一点)。

撰写回答