Repository: encode/django-rest-framework

Issue:
POSTing to framework throws: can only concatenate list (not "tuple") to list
In the method: 

def get_excluded_fieldnames(self):
        """
        Returns the fieldnames that should not be validated.
        """
        excluded_fields = list(self.opts.exclude)
        for field in self.fields.keys() + self.get_default_fields().keys():
            if self.opts.fields:
                if field not in self.opts.fields + self.opts.exclude:
                    excluded_fields.append(field)
        return excluded_fields

If no exclude is defined on the ModelSerialzer and fields are the code tries to add a tuple to a list and throws an error. Either self.opts.exclude should be changed to excluded_fields created earlier or the default for self.opts.fields and self.opts.exclude should be changed to lists instead of tuples



Discussion:
Hi @supercodepoet,

are you perhaps declaring fields as a list on your serializer, like so?:

```
class Meta:
    fields = ['my_fields']
```

Yes, I am declaring fields in my Meta

As a list or as a tuple?

As a list

You should be using a tuple.

ok, is this noted in the docs? I must have missed it

In all the examples, the fields options are declared as tuples indeed.

@markotibold You should be able to declare them using either. I simply use tuples because I prefer it by convention.
The + bit of code should cast everything to lists before doing the append.

Yeah, I would say usually in any place I see tuple or list I could use either. The self.opts.exclude list is converted to a list in the first line of the code so that + should use self.opts.exclude

Turns out Django mostly allows lists as well, e.g. with ModelForms. My bad, sorry @supercodepoet. 

Pull req coming up.

No problem, just glad I could help. haha, guess I should have submitted a Pull Request myself, sorry


Resolving patch:
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -132,9 +132,9 @@ def get_excluded_fieldnames(self):
         Returns the fieldnames that should not be validated.
         """
         excluded_fields = list(self.opts.exclude)
-        for field in self.fields.keys() + self.get_default_fields().keys():
-            if self.opts.fields:
-                if field not in self.opts.fields + self.opts.exclude:
+        if self.opts.fields:
+            for field in self.fields.keys() + self.get_default_fields().keys():
+                if field not in list(self.opts.fields) + excluded_fields:
                     excluded_fields.append(field)
         return excluded_fields
 


Test patch:
diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py
--- a/rest_framework/tests/serializer.py
+++ b/rest_framework/tests/serializer.py
@@ -66,6 +66,7 @@ class AlbumsSerializer(serializers.ModelSerializer):
 
     class Meta:
         model = Album
+        fields = ['title']  # lists are also valid options
 
 
 class BasicTests(TestCase):
@@ -282,9 +283,11 @@ def test_default_modelfield_max_length_exceeded(self):
         self.assertEquals(serializer.is_valid(), False)
         self.assertEquals(serializer.errors, {'info': [u'Ensure this value has at most 12 characters (it has 13).']})
 
+
+class ModelValidationTests(TestCase):
     def test_validate_unique(self):
         """
-        Just check if serializers.ModelSerializer.perform_model_validation() handles unique checks via .full_clean()
+        Just check if serializers.ModelSerializer handles unique checks via .full_clean()
         """
         serializer = AlbumsSerializer(data={'title': 'a'})
         serializer.is_valid()