Repository: encode/django-rest-framework

Issue:
Error in FileField validation with files=None
In FileField validation, if serializer.files is None, a typeerror will be raised.
This happens when parsing anything except `multipart/form-data` (which can be used if the file is not required).

Traceback:

```
  File "***/rest_framework/views.py", line 363, in dispatch
    response = self.handle_exception(exc)
  File "***/rest_framework/views.py", line 360, in dispatch
    response = handler(request, *args, **kwargs)
  File "***/rest_framework/generics.py", line 172, in put
    return self.update(request, *args, **kwargs)
  File "***/rest_framework/mixins.py", line 94, in update
    if serializer.is_valid():
  File "***/rest_framework/serializers.py", line 328, in is_valid
    return not self.errors
  File "***/rest_framework/serializers.py", line 322, in errors
    obj = self.from_native(self.init_data, self.init_files)
  File "***/rest_framework/serializers.py", line 283, in from_native
    attrs = self.restore_fields(data, files)
  File "***/rest_framework/serializers.py", line 214, in restore_fields
    field.field_from_native(data, files, field_name, reverted_data)
  File "***/rest_framework/fields.py", line 184, in field_from_native
    native = files[field_name]
TypeError: 'NoneType' object has no attribute '__getitem__'
```

For example, if the content-type is `application/x-www-form-urlencoded`, FormParser() will set the `files` to None:
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/parsers.py#L98

Then the field validator tries to find the field in `files`:
https://github.com/tomchristie/django-rest-framework/blob/2.1.14/rest_framework/fields.py#L183



Discussion:
Not sure what would be a better way to fix it - to typecheck `files` before calling `files[field_name]`, or making all parsers return an empty MultiValuedDict for data regardless of it's presence...

Not passing a files argument to a serializer is valid, so I'd say do `files = files or {}` prior to https://github.com/tomchristie/django-rest-framework/blob/2.1.14/rest_framework/fields.py#L183

I've given you the commit bit, so once this has a test, fix and a note in release notes, you're free to perform the merge yourself.  (Tho please do so via a pull req and wait for travis tests as usual)

Cheers! :)

Wow, thanks... :)


Resolving patch:
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -181,6 +181,7 @@ def field_from_native(self, data, files, field_name, into):
 
         try:
             if self._use_files:
+                files = files or {}
                 native = files[field_name]
             else:
                 native = data[field_name]


Test patch:
diff --git a/rest_framework/tests/files.py b/rest_framework/tests/files.py
--- a/rest_framework/tests/files.py
+++ b/rest_framework/tests/files.py
@@ -25,7 +25,6 @@ def restore_object(self, attrs, instance=None):
 
 
 class FileSerializerTests(TestCase):
-
     def test_create(self):
         now = datetime.datetime.now()
         file = StringIO.StringIO('stuff')
@@ -37,3 +36,16 @@ def test_create(self):
         self.assertEquals(serializer.object.created, uploaded_file.created)
         self.assertEquals(serializer.object.file, uploaded_file.file)
         self.assertFalse(serializer.object is uploaded_file)
+
+    def test_creation_failure(self):
+        """
+        Passing files=None should result in an ValidationError
+
+        Regression test for:
+        https://github.com/tomchristie/django-rest-framework/issues/542
+        """
+        now = datetime.datetime.now()
+
+        serializer = UploadedFileSerializer(data={'created': now})
+        self.assertFalse(serializer.is_valid())
+        self.assertIn('file', serializer.errors)