From cd546fdaee5f9f58c1c73b6ee93d0f1b19e02790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Be=CC=81al?= Date: Sat, 17 Mar 2012 20:27:01 +0900 Subject: [PATCH 1/3] raise 401 instead of 403 when user is not authenticated --- djangorestframework/permissions.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/djangorestframework/permissions.py b/djangorestframework/permissions.py index 03d78c2ea..d11740831 100644 --- a/djangorestframework/permissions.py +++ b/djangorestframework/permissions.py @@ -23,6 +23,11 @@ __all__ = ( SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS'] +_401_UNAUTHORIZED = ErrorResponse( + status.HTTP_401_UNAUTHORIZED, + {'detail': 'The request requires user authentication.'}, + {'WWW-Authenticate': 'Basic realm="API"'}) + _403_FORBIDDEN_RESPONSE = ErrorResponse( status.HTTP_403_FORBIDDEN, {'detail': 'You do not have permission to access this resource. ' + @@ -66,7 +71,7 @@ class IsAuthenticated(BasePermission): def check_permission(self, user): if not user.is_authenticated(): - raise _403_FORBIDDEN_RESPONSE + raise _401_UNAUTHORIZED class IsAdminUser(BasePermission): From 2edf4440511a04e703c0e1270f6012e1c9e1ea9c Mon Sep 17 00:00:00 2001 From: Sebastien Beal Date: Sun, 23 Dec 2012 07:40:15 +0900 Subject: [PATCH 2/3] create multiple objects at once with serializer --- rest_framework/serializers.py | 10 +++++-- rest_framework/tests/serializer.py | 48 +++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 8156bc185..970227331 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -257,7 +257,7 @@ class BaseSerializer(Field): You should override this method to control how deserialized objects are instantiated. """ - if instance is not None: + if instance is not None and not hasattr(instance, '__iter__'): instance.update(attrs) return instance return attrs @@ -276,7 +276,7 @@ class BaseSerializer(Field): """ if hasattr(data, '__iter__') and not isinstance(data, dict): # TODO: error data when deserializing lists - return (self.from_native(item) for item in data) + return [self.from_native(item, files) for item in data] self._errors = {} if data is not None or files is not None: @@ -334,7 +334,11 @@ class BaseSerializer(Field): """ Save the deserialized object and return it. """ - self.object.save() + if hasattr(self.object, '__iter__'): + for obj in self.object: + obj.save() + else: + self.object.save() return self.object diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 6ea4b4246..05d976400 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -34,7 +34,7 @@ class CommentSerializer(serializers.Serializer): sub_comment = serializers.Field(source='get_sub_comment.sub_comment') def restore_object(self, data, instance=None): - if instance is None: + if instance is None or hasattr(instance, '__iter__'): return Comment(**data) for key, val in data.items(): setattr(instance, key, val) @@ -831,3 +831,49 @@ class NestedSerializerContextTests(TestCase): # This will raise RuntimeError if context doesn't get passed correctly to the nested Serializers AlbumCollectionSerializer(album_collection, context={'context_item': 'album context'}).data + + +class MultipleObjectsTests(TestCase): + def setUp(self): + self.comments = [Comment( + 'tom@example.com', + 'Happy new year!', + datetime.datetime(2012, 1, 1) + ), + Comment( + 'seb@example.com', + 'Thank you!', + datetime.datetime(2012, 1, 2) + )] + self.data = [{ + 'email': 'tom@example.com', + 'content': 'Happy new year!', + 'created': datetime.datetime(2012, 1, 1), + 'sub_comment': 'This wont change' + }, + { + 'email': 'seb@example.com', + 'content': 'Thank you!', + 'created': datetime.datetime(2012, 1, 2), + 'sub_comment': 'This wont change' + }] + self.expected = [{ + 'email': 'tom@example.com', + 'content': 'Happy new year!', + 'created': datetime.datetime(2012, 1, 1), + 'sub_comment': 'And Merry Christmas!' + }, + { + 'email': 'seb@example.com', + 'content': 'Thank you!', + 'created': datetime.datetime(2012, 1, 2), + 'sub_comment': 'And Merry Christmas!' + }] + + def test_create(self): + serializer = CommentSerializer(data=self.data) + expected = self.comments + self.assertEquals(serializer.is_valid(), True) + self.assertEquals(serializer.object, expected) + self.assertFalse(serializer.object is expected) + self.assertEquals(serializer.data, self.expected) From 1128fe3bafef3555895a050db112bcedb50f9805 Mon Sep 17 00:00:00 2001 From: Sebastien Beal Date: Sat, 29 Dec 2012 12:01:55 +0900 Subject: [PATCH 3/3] multiple object updates introducing a _instance attribute to the Serializer --- rest_framework/serializers.py | 10 ++++++++-- rest_framework/tests/serializer.py | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 970227331..d7bb47fd5 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -118,6 +118,7 @@ class BaseSerializer(Field): self._data = None self._files = None self._errors = None + self._instance = instance ##### # Methods to determine which fields to use when (de)serializing objects. @@ -276,7 +277,12 @@ class BaseSerializer(Field): """ if hasattr(data, '__iter__') and not isinstance(data, dict): # TODO: error data when deserializing lists - return [self.from_native(item, files) for item in data] + objects = [] + for i, item in enumerate(data): + if hasattr(self.object, '__iter__'): + self._instance = self.object[i] + objects.append(self.from_native(item, files)) + return objects self._errors = {} if data is not None or files is not None: @@ -286,7 +292,7 @@ class BaseSerializer(Field): self._errors['non_field_errors'] = ['No input provided'] if not self._errors: - return self.restore_object(attrs, instance=getattr(self, 'object', None)) + return self.restore_object(attrs, instance=getattr(self, '_instance', None)) def field_to_native(self, obj, field_name): """ diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 05d976400..1b9da2dcb 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -877,3 +877,12 @@ class MultipleObjectsTests(TestCase): self.assertEquals(serializer.object, expected) self.assertFalse(serializer.object is expected) self.assertEquals(serializer.data, self.expected) + + def test_update(self): + serializer = CommentSerializer(instance=self.comments, data=self.data) + expected = self.comments + self.assertEquals(serializer.is_valid(), True) + self.assertEquals(serializer.object, expected) + for obj, exp in zip(serializer.object, expected): + self.assertTrue(obj is exp) + self.assertEquals(serializer.data, self.expected)