Added handling of validation errors in PUT-as-create.

Fixes #1035.
This commit is contained in:
Krzysztof Jurewicz 2013-11-19 15:49:31 +01:00
parent ca2bd616d9
commit 9cea6880f7
2 changed files with 24 additions and 3 deletions

View File

@ -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)

View File

@ -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