Skip to content

Commit d27b8cc

Browse files
committed
PUT as create docs, and move mixin out to external gist
1 parent 3784596 commit d27b8cc

File tree

3 files changed

+15
-49
lines changed

3 files changed

+15
-49
lines changed

docs/api-guide/generic-views.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,20 @@ If you are using a mixin across multiple views, you can take this a step further
368368

369369
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.
370370

371+
---
372+
373+
# PUT as create
374+
375+
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.
376+
377+
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.
378+
379+
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.
380+
381+
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.
382+
383+
---
384+
371385
# Third party packages
372386

373387
The following third party packages provide additional generic view implementations.

docs/topics/3.0-announcement.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ Allowing `PUT` as create operations is problematic, as it necessarily exposes in
694694

695695
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.
696696

697-
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`.
697+
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.
698698

699699
#### Customizing error responses.
700700

rest_framework/mixins.py

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
"""
77
from __future__ import unicode_literals
88

9-
from django.http import Http404
109
from rest_framework import status
1110
from rest_framework.response import Response
12-
from rest_framework.request import clone_request
1311
from rest_framework.settings import api_settings
1412

1513

@@ -89,49 +87,3 @@ def destroy(self, request, *args, **kwargs):
8987

9088
def perform_destroy(self, instance):
9189
instance.delete()
92-
93-
94-
# The AllowPUTAsCreateMixin was previously the default behaviour
95-
# for PUT requests. This has now been removed and must be *explicitly*
96-
# included if it is the behavior that you want.
97-
# For more info see: ...
98-
99-
class AllowPUTAsCreateMixin(object):
100-
"""
101-
The following mixin class may be used in order to support PUT-as-create
102-
behavior for incoming requests.
103-
"""
104-
def update(self, request, *args, **kwargs):
105-
partial = kwargs.pop('partial', False)
106-
instance = self.get_object_or_none()
107-
serializer = self.get_serializer(instance, data=request.data, partial=partial)
108-
serializer.is_valid(raise_exception=True)
109-
110-
if instance is None:
111-
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
112-
lookup_value = self.kwargs[lookup_url_kwarg]
113-
extra_kwargs = {self.lookup_field: lookup_value}
114-
serializer.save(**extra_kwargs)
115-
return Response(serializer.data, status=status.HTTP_201_CREATED)
116-
117-
serializer.save()
118-
return Response(serializer.data)
119-
120-
def partial_update(self, request, *args, **kwargs):
121-
kwargs['partial'] = True
122-
return self.update(request, *args, **kwargs)
123-
124-
def get_object_or_none(self):
125-
try:
126-
return self.get_object()
127-
except Http404:
128-
if self.request.method == 'PUT':
129-
# For PUT-as-create operation, we need to ensure that we have
130-
# relevant permissions, as if this was a POST request. This
131-
# will either raise a PermissionDenied exception, or simply
132-
# return None.
133-
self.check_permissions(clone_request(self.request, 'POST'))
134-
else:
135-
# PATCH requests where the object does not exist should still
136-
# return a 404 response.
137-
raise

0 commit comments

Comments
 (0)