diff options
| -rw-r--r-- | rest_framework/mixins.py | 8 | ||||
| -rw-r--r-- | rest_framework/tests/test_generics.py | 19 | 
2 files changed, 24 insertions, 3 deletions
diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py index 4606c78b..79f79c30 100644 --- a/rest_framework/mixins.py +++ b/rest_framework/mixins.py @@ -6,6 +6,7 @@ which allows mixin classes to be composed in interesting ways.  """  from __future__ import unicode_literals +from django.core.exceptions import ValidationError  from django.http import Http404  from rest_framework import status  from rest_framework.response import Response @@ -127,7 +128,12 @@ class UpdateModelMixin(object):                                           files=request.FILES, partial=partial)          if serializer.is_valid(): -            self.pre_save(serializer.object) +            try: +                self.pre_save(serializer.object) +            except ValidationError as err: +                # full_clean on model instance may be called in pre_save, so we +                # have to handle eventual errors. +                return Response(err.message_dict, status=status.HTTP_400_BAD_REQUEST)              self.object = serializer.save(**save_kwargs)              self.post_save(self.object, created=created)              return Response(serializer.data, status=success_status_code) diff --git a/rest_framework/tests/test_generics.py b/rest_framework/tests/test_generics.py index 3fcef606..996bd5b0 100644 --- a/rest_framework/tests/test_generics.py +++ b/rest_framework/tests/test_generics.py @@ -23,6 +23,10 @@ class InstanceView(generics.RetrieveUpdateDestroyAPIView):      """      model = BasicModel +    def get_queryset(self): +        queryset = super(InstanceView, self).get_queryset() +        return queryset.exclude(text='filtered out') +  class SlugSerializer(serializers.ModelSerializer):      slug = serializers.Field()  # read only @@ -160,10 +164,10 @@ class TestInstanceView(TestCase):          """          Create 3 BasicModel intances.          """ -        items = ['foo', 'bar', 'baz'] +        items = ['foo', 'bar', 'baz', 'filtered out']          for item in items:              BasicModel(text=item).save() -        self.objects = BasicModel.objects +        self.objects = BasicModel.objects.exclude(text='filtered out')          self.data = [              {'id': obj.id, 'text': obj.text}              for obj in self.objects.all() @@ -352,6 +356,17 @@ class TestInstanceView(TestCase):          updated = self.objects.get(id=1)          self.assertEqual(updated.text, 'foobar') +    def test_put_to_filtered_out_instance(self): +        """ +        PUT requests to an URL of instance which is filtered out should not be +        able to create new objects. +        """ +        data = {'text': 'foo'} +        filtered_out_pk = BasicModel.objects.filter(text='filtered out')[0].pk +        request = factory.put('/{0}'.format(filtered_out_pk), data, format='json') +        response = self.view(request, pk=filtered_out_pk).render() +        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) +      def test_put_as_create_on_id_based_url(self):          """          PUT requests to RetrieveUpdateDestroyAPIView should create an object  | 
