diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 9820cb403..c7db32edf 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -41,7 +41,9 @@ Defaults to `True`. ### `default` -If set, this gives the default value that will be used for the field if none is supplied. If not set the default behavior is to not populate the attribute at all. +If set, this gives the default value that will be used for the field if none is supplied. If not set the default behavior is to not populate the attribute at all. + +May be set to a function or other callable, in which case the value will be evaluated each time it is used. ### `validators` diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 77cd4f9ea..6eb181603 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -43,6 +43,7 @@ You can determine your currently installed version using `pip freeze`: ### Master * Added `get_url` hook to `HyperlinkedIdentityField`. +* Serializer field `default` argument may be a callable. * Bugfix: The `lookup_field` option on `HyperlinkedIdentityField` should apply by default to the url field on the serializer. * Bugfix: `HyperlinkedIdentityField` should continue to support `pk_url_kwarg`, `slug_url_kwarg`, `slug_field`, in a pending deprecation state. * Bugfix: Ensure we always return 404 instead of 500 if a lookup field cannot be converted to the correct lookup type. (Eg non-numeric `AutoInteger` pk lookup) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 30bbafc41..535aa2ac8 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -250,9 +250,6 @@ class WritableField(Field): self.validators = self.default_validators + validators self.default = default if default is not None else self.default - if is_simple_callable(self.default): - self.default = self.default() - # Widgets are ony used for HTML forms. widget = widget or self.widget if isinstance(widget, type): @@ -298,7 +295,10 @@ class WritableField(Field): except KeyError: if self.default is not None and not self.partial: # Note: partial updates shouldn't set defaults - native = self.default + if is_simple_callable(self.default): + native = self.default() + else: + native = self.default else: if self.required: raise ValidationError(self.error_messages['required']) diff --git a/rest_framework/tests/test_fields.py b/rest_framework/tests/test_fields.py index 3f9560516..de3710011 100644 --- a/rest_framework/tests/test_fields.py +++ b/rest_framework/tests/test_fields.py @@ -852,3 +852,17 @@ class FieldMetadata(TestCase): def test_label(self): for field in (self.required_field, self.optional_field): self.assertEqual(field.metadata()['label'], field.label) + + +class FieldCallableDefault(TestCase): + def setUp(self): + self.simple_callable = lambda: 'foo bar' + + def test_default_can_be_simple_callable(self): + """ + Ensure that the 'default' argument can also be a simple callable. + """ + field = serializers.WritableField(default=self.simple_callable) + into = {} + field.field_from_native({}, {}, 'field', into) + self.assertEquals(into, {'field': 'foo bar'})