Repository: encode/django-rest-framework

Issue:
ModelSerializer custom named field source evaluates to True instead of field_name
## Checklist

- [x] I have verified that that issue exists against the `master` branch of Django REST framework.
- [x] I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
- [x] This is not a usage question. (Those should be directed to the [discussion group](https://groups.google.com/forum/#!forum/django-rest-framework) instead.)
- [x] This cannot be dealt with as a third party library. (We prefer new functionality to be [in the form of third party libraries](http://www.django-rest-framework.org/topics/third-party-resources/#about-third-party-packages) where possible.)
- [x] I have reduced the issue to the simplest possible case.
- [x] I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)

## Steps to reproduce

1. Create a `ModelSerializer` including a field in `Meta` with a custom name (that isn't on the model).
2. Set the source of the field, in `extra_kwargs` to a named field within the model.
3. Initialise the Serializer.

## Expected behavior

- Creates a Serializer with a field with a custom field name, that has it's source as the specified field on the Model.

## Actual behavior

- `TypeError: hasattr(): attribute name must be string`

Caused by #5138 when accounting for `*`-sourced fields.

https://github.com/encode/django-rest-framework/blob/79be20a7c68e7c90dd4d5d23a9e6ee08b5f586ae/rest_framework/serializers.py#L1013

In the case that `source` is specified AND is not `'*'`,
`extra_field_kwargs.get('source', '*') != '*'` evaluates to `True`, and thus `source = True`,
leading to the `TypeError`

Pull Request with test that fails on master, and fix: #5388



Discussion:

Resolving patch:
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -1010,7 +1010,9 @@ def get_fields(self):
                 continue
 
             extra_field_kwargs = extra_kwargs.get(field_name, {})
-            source = extra_field_kwargs.get('source', '*') != '*' or field_name
+            source = extra_field_kwargs.get('source', '*')
+            if source == '*':
+                source = field_name
 
             # Determine the serializer field class and keyword arguments.
             field_class, field_kwargs = self.build_field(


Test patch:
diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py
--- a/tests/test_model_serializer.py
+++ b/tests/test_model_serializer.py
@@ -1135,3 +1135,24 @@ class Meta:
         serializer = TestUniqueChoiceSerializer(data={'name': 'choice1'})
         assert not serializer.is_valid()
         assert serializer.errors == {'name': ['unique choice model with this name already exists.']}
+
+
+class TestFieldSource(TestCase):
+    def test_named_field_source(self):
+        class TestSerializer(serializers.ModelSerializer):
+
+            class Meta:
+                model = RegularFieldsModel
+                fields = ('number_field',)
+                extra_kwargs = {
+                    'number_field': {
+                        'source': 'integer_field'
+                    }
+                }
+
+        expected = dedent("""
+            TestSerializer():
+                number_field = IntegerField(source='integer_field')
+        """)
+        self.maxDiff = None
+        self.assertEqual(unicode_repr(TestSerializer()), expected)