From de5b071d677074ab3b6b33a843c4b05ba2052a6b Mon Sep 17 00:00:00 2001 From: Jamie Matthews Date: Mon, 19 Nov 2012 17:22:17 +0000 Subject: [PATCH] Add SerializerMethodField --- docs/api-guide/fields.md | 6 ++++++ rest_framework/fields.py | 14 ++++++++++++ rest_framework/tests/serializer.py | 34 ++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index d1c31ecc7..b19c324ad 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -324,5 +324,11 @@ This field is always read-only. * `pk_url_kwarg` - The named url parameter for the pk field lookup. Default is `pk`. * `slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`. +# Other Fields + +## SerializerMethodField + +This is a read-only field gets its value by calling a method on the serializer class it's attached to. It can be used to add any sort of data to the serialized representation of your object. The field's constructor accepts a single argument, which is the name of the method on the serializer to be called. The method should accept a single argument (in addition to `self`), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. + [cite]: http://www.python.org/dev/peps/pep-0020/ [FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS diff --git a/rest_framework/fields.py b/rest_framework/fields.py index c68c39b59..d1e9c45d8 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1019,3 +1019,17 @@ class ImageField(FileField): if hasattr(f, 'seek') and callable(f.seek): f.seek(0) return f + + +class SerializerMethodField(Field): + """ + A field that gets its value by calling a method on the serializer it's attached to. + """ + + def __init__(self, method_name): + self.method_name = method_name + super(SerializerMethodField, self).__init__() + + def field_to_native(self, obj, field_name): + value = getattr(self.parent, self.method_name)(obj) + return self.to_native(value) diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index fb1be7eb0..cc6e9d5cf 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -497,6 +497,40 @@ class ManyRelatedTests(TestCase): self.assertEqual(serializer.data, expected) +class SerializerMethodFieldTests(TestCase): + def setUp(self): + + class BoopSerializer(serializers.Serializer): + beep = serializers.SerializerMethodField('get_beep') + boop = serializers.Field() + boop_count = serializers.SerializerMethodField('get_boop_count') + + def get_beep(self, obj): + return 'hello!' + + def get_boop_count(self, obj): + return len(obj.boop) + + self.serializer_class = BoopSerializer + + def test_serializer_method_field(self): + + class MyModel(object): + boop = ['a', 'b', 'c'] + + source_data = MyModel() + + serializer = self.serializer_class(source_data) + + expected = { + 'beep': u'hello!', + 'boop': [u'a', u'b', u'c'], + 'boop_count': 3, + } + + self.assertEqual(serializer.data, expected) + + # Test for issue #324 class BlankFieldTests(TestCase): def setUp(self):