Сериализация методов @property в классе Python - PullRequest
16 голосов
/ 06 апреля 2010

Есть ли способ передать какие-либо определения @property в сериализатор json при сериализации класса модели Django?

пример:

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 ]

12 голосов
/ 09 апреля 2010

Вы можете расширить сериализаторы 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 в дополнение к изменению базовый класс, чтобы сделать это).

5 голосов
/ 07 июля 2016

Решение сработало хорошо, предложенное М. Рафеем Алием и 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' ...])
5 голосов
/ 13 мая 2015

С 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', ...])
3 голосов
/ 27 января 2017

Это комбинация ответа М. Рафая Алима и Вотоверса и каотса. Это СУХОЙ и позволяет вам указать только дополнительные реквизиты вместо всех полей и реквизитов, как в версии 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', ...])
0 голосов
/ 06 апреля 2010

Вы можете получить все свойства класса, используя черную магию:

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

Например:

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

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

Затем вы можете построить словарь и сериализовать его оттуда.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...