From 2533c2452b383771f80e6d40c93ae4a5ef6a8cf7 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 5 Oct 2012 16:24:52 +0100 Subject: [PATCH] Support PUT for create --- rest_framework/mixins.py | 27 ++++++++++++++++++++++++++- rest_framework/tests/generics.py | 15 +++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py index e3c7cf037..46821f643 100644 --- a/rest_framework/mixins.py +++ b/rest_framework/mixins.py @@ -71,13 +71,38 @@ class UpdateModelMixin(object): Should be mixed in with `SingleObjectBaseView`. """ def update(self, request, *args, **kwargs): - self.object = self.get_object() + try: + self.object = self.get_object() + except Http404: + self.object = None + serializer = self.get_serializer(data=request.DATA, instance=self.object) if serializer.is_valid(): + if self.object is None: + obj = serializer.object + # TODO: Make ModelSerializers return regular instances, + # not DeserializedObject + if hasattr(obj, 'object'): + obj = obj.object + self.update_urlconf_attributes(serializer.object.object) self.object = serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + def update_urlconf_attributes(self, obj): + """ + When update (re)creates an object, we need to set any attributes that + are tied to the URLconf. + """ + pk = self.kwargs.get(self.pk_url_kwarg, None) + if pk: + setattr(obj, 'pk', pk) + + slug = self.kwargs.get(self.slug_url_kwarg, None) + if slug: + slug_field = self.get_slug_field() + setattr(obj, slug_field, slug) + class DestroyModelMixin(object): """ diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index c0645d6ee..2a6a0744e 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -208,3 +208,18 @@ class TestInstanceView(TestCase): self.assertEquals(response.data, {'id': 1, 'text': 'foobar'}) updated = self.objects.get(id=1) self.assertEquals(updated.text, 'foobar') + + def test_put_to_deleted_instance(self): + """ + PUT requests to RetrieveUpdateDestroyAPIView should create an object + if it does not currently exist. + """ + self.objects.get(id=1).delete() + content = {'text': 'foobar'} + request = factory.put('/1', json.dumps(content), + content_type='application/json') + response = self.view(request, pk=1).render() + self.assertEquals(response.status_code, status.HTTP_200_OK) + self.assertEquals(response.data, {'id': 1, 'text': 'foobar'}) + updated = self.objects.get(id=1) + self.assertEquals(updated.text, 'foobar')