Repository: encode/django-rest-framework

Issue:
None and source="*" compatibility
This:

``` python
class TestField(serializers.Field):
    def __init__(self, *args, **kwargs):
        kwargs['source'] = '*'
        super(TestField, self).__init__(*args, **kwargs)

    def to_representation(self, value):
        return value

    def to_internal_value(self, data):
        return data


class TestSerializer(serializers.Serializer):
    f = TestField(allow_null=True)

s = TestSerializer(data={"f": None})
s.is_valid(raise_exception=True)
```

Results in :

```
  131.         s.is_valid(raise_exception=True)
File "/projects/test/env/local/lib/python2.7/site-packages/rest_framework/serializers.py" in is_valid
  202.                 self._validated_data = self.run_validation(self.initial_data)
File "/projects/test/env/local/lib/python2.7/site-packages/rest_framework/serializers.py" in run_validation
  396.         value = self.to_internal_value(data)
File "projects/test/env/local/lib/python2.7/site-packages/rest_framework/serializers.py" in to_internal_value
  436.                 set_value(ret, field.source_attrs, validated_value)
File "projects/test/env/local/lib/python2.7/site-packages/rest_framework/fields.py" in set_value
  101.         dictionary.update(value)
File "/projects/test/env/lib/python2.7/_abcoll.py" in update
  547.             for key, value in other:
```

Tested: 3.1.1, 3.2.4
What's expected behavior here?



Discussion:
Probably worth expanding on this with what you're expecting to see here?

Unless i'm missing something, None in data. Non null values work just fine.

I'm having problems when I change the field of ModelSerializer to relate a serializer field name to a model field name using source argument.

``` python
class ArticleSerializer(serializer.ModelSerializer):
    user_id = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all(), source='user',
        required=False, allow_null=True)
```

I solved overwriting the `to_internal_value` and `to_representation` method of PrimaryKeryRelatedField. But I don't think this is the best solution:

``` python
class AllowNullPKField(serializers.PrimaryKeyRelatedField):
    def to_internal_value(self, data):
        if data == 'None':
            return None
        return super(AllowNullPKField, self).to_internal_value(data)

    def to_representation(self, value):
        if value is None:
            return None
        return super(AllowNullPKField, self).to_representation(value)


class ArticleSerializer(serializer.ModelSerializer):
    user_id = AllowNullPKField(
        queryset=User.objects.all(), source='user',
        required=False, allow_null=True)
```


Resolving patch:
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -493,6 +493,11 @@ def validate_empty_values(self, data):
         if data is None:
             if not self.allow_null:
                 self.fail('null')
+            # Nullable `source='*'` fields should not be skipped when its named
+            # field is given a null value. This is because `source='*'` means
+            # the field is passed the entire object, which is not null.
+            elif self.source == '*':
+                return (False, None)
             return (True, None)
 
         return (False, data)


Test patch:
diff --git a/tests/test_serializer.py b/tests/test_serializer.py
--- a/tests/test_serializer.py
+++ b/tests/test_serializer.py
@@ -317,7 +317,8 @@ def test_validate_list(self):
 
 class TestStarredSource:
     """
-    Tests for `source='*'` argument, which is used for nested representations.
+    Tests for `source='*'` argument, which is often used for complex field or
+    nested representations.
 
     For example:
 
@@ -337,11 +338,28 @@ class NestedSerializer2(serializers.Serializer):
             c = serializers.IntegerField()
             d = serializers.IntegerField()
 
-        class TestSerializer(serializers.Serializer):
+        class NestedBaseSerializer(serializers.Serializer):
             nested1 = NestedSerializer1(source='*')
             nested2 = NestedSerializer2(source='*')
 
-        self.Serializer = TestSerializer
+        # nullable nested serializer testing
+        class NullableNestedSerializer(serializers.Serializer):
+            nested = NestedSerializer1(source='*', allow_null=True)
+
+        # nullable custom field testing
+        class CustomField(serializers.Field):
+            def to_representation(self, instance):
+                return getattr(instance, 'foo', None)
+
+            def to_internal_value(self, data):
+                return {'foo': data}
+
+        class NullableFieldSerializer(serializers.Serializer):
+            field = CustomField(source='*', allow_null=True)
+
+        self.Serializer = NestedBaseSerializer
+        self.NullableNestedSerializer = NullableNestedSerializer
+        self.NullableFieldSerializer = NullableFieldSerializer
 
     def test_nested_validate(self):
         """
@@ -356,6 +374,12 @@ def test_nested_validate(self):
             'd': 4
         }
 
+    def test_nested_null_validate(self):
+        serializer = self.NullableNestedSerializer(data={'nested': None})
+
+        # validation should fail (but not error) since nested fields are required
+        assert not serializer.is_valid()
+
     def test_nested_serialize(self):
         """
         An object can be serialized into a nested representation.
@@ -364,6 +388,20 @@ def test_nested_serialize(self):
         serializer = self.Serializer(instance)
         assert serializer.data == self.data
 
+    def test_field_validate(self):
+        serializer = self.NullableFieldSerializer(data={'field': 'bar'})
+
+        # validation should pass since no internal validation
+        assert serializer.is_valid()
+        assert serializer.validated_data == {'foo': 'bar'}
+
+    def test_field_null_validate(self):
+        serializer = self.NullableFieldSerializer(data={'field': None})
+
+        # validation should pass since no internal validation
+        assert serializer.is_valid()
+        assert serializer.validated_data == {'foo': None}
+
 
 class TestIncorrectlyConfigured:
     def test_incorrect_field_name(self):