mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-02 19:40:13 +03:00
Add support for passing callable as source
argument for a field.
Sometimes it is desirable that the serialized form will contain a field that is not directly accessible through a model attribute or method. That may happen, for instance, if you are serializing a third-party model which you cannot modify. This change adds support for passing a callable as a `source` argument for a field. That callable accepts a single argument which is the object being serialized, and in turn, returns the value that goes into the field.
This commit is contained in:
parent
f1251e8c58
commit
9eba60f5b0
|
@ -20,7 +20,7 @@ Each serializer field class constructor takes at least these arguments. Some Fi
|
|||
|
||||
### `source`
|
||||
|
||||
The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `Field(source='get_absolute_url')`, or may use dotted notation to traverse attributes, such as `Field(source='user.email')`.
|
||||
The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `Field(source='get_absolute_url')`, or may use dotted notation to traverse attributes, such as `Field(source='user.email')`. Alternatively, `source` can be a callable that takes a single argument (the object being serialized) and returns the value that will populate this field.
|
||||
|
||||
The value `source='*'` has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations. (See the implementation of the `PaginationSerializer` class for an example.)
|
||||
|
||||
|
|
|
@ -160,6 +160,9 @@ class Field(object):
|
|||
source = self.source or field_name
|
||||
value = obj
|
||||
|
||||
if callable(source):
|
||||
return source(value)
|
||||
|
||||
for component in source.split('.'):
|
||||
value = get_component(value, component)
|
||||
if value is None:
|
||||
|
|
|
@ -803,6 +803,26 @@ class CallableDefaultValueTests(TestCase):
|
|||
self.assertEqual(instance.text, 'overridden')
|
||||
|
||||
|
||||
class CallableSourceTests(TestCase):
|
||||
def setUp(self):
|
||||
class CommentSerializer(serializers.Serializer):
|
||||
email = serializers.EmailField()
|
||||
content = serializers.CharField(max_length=1000)
|
||||
length = serializers.IntegerField(
|
||||
source=lambda comment: len(comment.content),
|
||||
read_only=True)
|
||||
self.serializer_class = CommentSerializer
|
||||
|
||||
def test_callable_source(self):
|
||||
instance = Comment('user@email.com', 'foobar', None)
|
||||
serializer = self.serializer_class(instance=instance)
|
||||
self.assertEquals(serializer.data, {
|
||||
'email': 'user@email.com',
|
||||
'content': 'foobar',
|
||||
'length': 6
|
||||
})
|
||||
|
||||
|
||||
class ManyRelatedTests(TestCase):
|
||||
def test_reverse_relations(self):
|
||||
post = BlogPost.objects.create(title="Test blog post")
|
||||
|
|
Loading…
Reference in New Issue
Block a user