aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Christie2014-11-03 12:00:19 +0000
committerTom Christie2014-11-03 12:00:19 +0000
commitd27b8cc09b83bac10346effa1021493d2835b794 (patch)
treed9e7ff7ee173c1844734f16d0bf6fa2055088076
parent37845968cd66e6372bbc22fd3ced131dff3b824a (diff)
downloaddjango-rest-framework-d27b8cc09b83bac10346effa1021493d2835b794.tar.bz2
PUT as create docs, and move mixin out to external gist
-rwxr-xr-xdocs/api-guide/generic-views.md14
-rw-r--r--docs/topics/3.0-announcement.md2
-rw-r--r--rest_framework/mixins.py48
3 files changed, 15 insertions, 49 deletions
diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md
index 49be0cae..d2836fa6 100755
--- a/docs/api-guide/generic-views.md
+++ b/docs/api-guide/generic-views.md
@@ -368,6 +368,20 @@ If you are using a mixin across multiple views, you can take this a step further
Using custom base classes is a good option if you have custom behavior that consistently needs to be repeated across a large number of views throughout your project.
+---
+
+# PUT as create
+
+Prior to version 3.0 the REST framework mixins treated `PUT` as either an update or a create operation, depending on if the object already existed or not.
+
+Allowing `PUT` as create operations is problematic, as it necessarily exposes information about the existence or non-existance of objects. It's also not obvious that transparently allowing re-creating of previously deleted instances is necessarily a better default behavior than simply returning `404` responses.
+
+Both styles "`PUT` as 404" and "`PUT` as create" can be valid in different circumstances, but from version 3.0 onwards we now use 404 behavior as the default, due to it being simpler and more obvious.
+
+If you need to generic PUT-as-create behavior you may want to include something like [this `AllowPUTAsCreateMixin` class](https://gist.github.com/tomchristie/a2ace4577eff2c603b1b) as a mixin to your views.
+
+---
+
# Third party packages
The following third party packages provide additional generic view implementations.
diff --git a/docs/topics/3.0-announcement.md b/docs/topics/3.0-announcement.md
index f69c0b25..97ffdcf3 100644
--- a/docs/topics/3.0-announcement.md
+++ b/docs/topics/3.0-announcement.md
@@ -694,7 +694,7 @@ Allowing `PUT` as create operations is problematic, as it necessarily exposes in
Both styles "`PUT` as 404" and "`PUT` as create" can be valid in different circumstances, but we've now opted for the 404 behavior as the default, due to it being simpler and more obvious.
-If you need to restore the previous behavior you can include the `AllowPUTAsCreateMixin` class in your view. This class can be imported from `rest_framework.mixins`.
+If you need to restore the previous behavior you may want to include [this `AllowPUTAsCreateMixin` class](https://gist.github.com/tomchristie/a2ace4577eff2c603b1b) as a mixin to your views.
#### Customizing error responses.
diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py
index 467ff515..2074a107 100644
--- a/rest_framework/mixins.py
+++ b/rest_framework/mixins.py
@@ -6,10 +6,8 @@ which allows mixin classes to be composed in interesting ways.
"""
from __future__ import unicode_literals
-from django.http import Http404
from rest_framework import status
from rest_framework.response import Response
-from rest_framework.request import clone_request
from rest_framework.settings import api_settings
@@ -89,49 +87,3 @@ class DestroyModelMixin(object):
def perform_destroy(self, instance):
instance.delete()
-
-
-# The AllowPUTAsCreateMixin was previously the default behaviour
-# for PUT requests. This has now been removed and must be *explicitly*
-# included if it is the behavior that you want.
-# For more info see: ...
-
-class AllowPUTAsCreateMixin(object):
- """
- The following mixin class may be used in order to support PUT-as-create
- behavior for incoming requests.
- """
- def update(self, request, *args, **kwargs):
- partial = kwargs.pop('partial', False)
- instance = self.get_object_or_none()
- serializer = self.get_serializer(instance, data=request.data, partial=partial)
- serializer.is_valid(raise_exception=True)
-
- if instance is None:
- lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
- lookup_value = self.kwargs[lookup_url_kwarg]
- extra_kwargs = {self.lookup_field: lookup_value}
- serializer.save(**extra_kwargs)
- return Response(serializer.data, status=status.HTTP_201_CREATED)
-
- serializer.save()
- return Response(serializer.data)
-
- def partial_update(self, request, *args, **kwargs):
- kwargs['partial'] = True
- return self.update(request, *args, **kwargs)
-
- def get_object_or_none(self):
- try:
- return self.get_object()
- except Http404:
- if self.request.method == 'PUT':
- # For PUT-as-create operation, we need to ensure that we have
- # relevant permissions, as if this was a POST request. This
- # will either raise a PermissionDenied exception, or simply
- # return None.
- self.check_permissions(clone_request(self.request, 'POST'))
- else:
- # PATCH requests where the object does not exist should still
- # return a 404 response.
- raise