Serializar los métodos @property en una clase de Python

¿Hay alguna forma de pasar las definiciones de @property a un serializador json cuando se serializa una clase de modelo Django?

ejemplo:

class FooBar(object.Model) name = models.CharField(...) @property def foo(self): return "My name is %s" %self.name 

Quiere serializar a:

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

Puede extender los serializadores de Django sin mucho trabajo. Aquí hay un serializador personalizado que toma un queryset y una lista de atributos (campos o no), y devuelve 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) 

Uso:

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

Por supuesto, esto es probablemente más trabajo que solo escribir su propio serializador JSON más simple, pero tal vez no más trabajo que su propio serializador XML (tendría que redefinir “handle_field” para que coincida con el caso XML además de cambiar la clase base a Haz eso).

Las cosas han cambiado un poco desde 2010, por lo que la respuesta de @ user85461 parece que ya no funciona con Django 1.8 y Python 3.4. Esta es una respuesta actualizada con lo que parece funcionar para mí.

 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 

Uso:

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

La solución funcionó bien, propuesta por M. Rafay Aleem y Wtower, pero está duplicada en muchos códigos. Aquí hay una mejora:

 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 

Cómo usarlo:

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

Esta es una combinación de M. Rafay Aleem y Wtowers respuesta y caots. Esto es SECO y le permite especificar solo los apoyos adicionales en lugar de todos los campos y apoyos como en la versión 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 

Cómo usarlo:

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

Puedes obtener todas las propiedades de una clase usando magia negra:

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

Por ejemplo:

 >>> class Foo: @property def bar(self): return "bar" >>> list_class_properties(Foo) ['bar'] 

Entonces puedes construir el diccionario y serializarlo desde allí.