aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--rest_framework/mixins.py8
-rw-r--r--rest_framework/tests/test_generics.py19
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