Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit aa12b49

Browse files
Allow POST, PATCH, DELETE for actions in ReadOnlyModelViewSet (#797)
Currently if you try to use `POST` for action in `ReadOnlyModelViewSet` you will get problems: - with DRF UI you will loose data input forms - `drf_yasg` package will not generate OpenAPI specifications for such actions This behavior was added to `django-rest-framework-json-api` in version 2.8.0 by mistake: Commit: 7abd764 Subject: remove disallowed PUT method. (#643)
1 parent 073c45b commit aa12b49

File tree

4 files changed

+71
-1
lines changed

4 files changed

+71
-1
lines changed

‎AUTHORS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Raphael Cohen <raphael.cohen.utt@gmail.com>
1919
Roberto Barreda <roberto.barreda@gmail.com>
2020
Rohith PR <praroh2@gmail.com>
2121
santiavenda <santiavenda2@gmail.com>
22+
Sergey Kolomenkin <https://kolomenkin.com>
2223
Tim Selman <timcbaoth@gmail.com>
2324
Yaniv Peer <yanivpeer@gmail.com>
2425
Mohammed Ali Zubair <mazg1493@gmail.com>

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ any parts of the framework not mentioned in the documentation should generally b
1818

1919
* Avoid `AttributeError` for PUT and PATCH methods when using `APIView`
2020
* Clear many-to-many relationships instead of deleting related objects during PATCH on `RelationshipView`
21+
* Allow POST, PATCH, DELETE for actions in `ReadOnlyModelViewSet`. It was problematic since 2.8.0.
2122

2223
### Changed
2324

‎example/tests/test_views.py‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33

44
from django.test import RequestFactory
55
from django.utils import timezone
6+
from rest_framework import status
7+
from rest_framework.decorators import action
68
from rest_framework.exceptions import NotFound
79
from rest_framework.request import Request
10+
from rest_framework.response import Response
811
from rest_framework.reverse import reverse
912
from rest_framework.test import APIRequestFactory, APITestCase, force_authenticate
1013

14+
from rest_framework_json_api import serializers, views
1115
from rest_framework_json_api.utils import format_resource_type
1216

1317
from example.factories import AuthorFactory, CommentFactory, EntryFactory
@@ -634,3 +638,67 @@ def test_get_object_gives_correct_entry(self):
634638
}
635639
got = resp.json()
636640
self.assertEqual(got, expected)
641+
642+
643+
class BasicAuthorSerializer(serializers.ModelSerializer):
644+
class Meta:
645+
model = Author
646+
fields = ('name',)
647+
648+
649+
class ReadOnlyViewSetWithCustomActions(views.ReadOnlyModelViewSet):
650+
queryset = Author.objects.all()
651+
serializer_class = BasicAuthorSerializer
652+
653+
@action(detail=False, methods=['post', 'patch', 'delete'])
654+
def group_action(self, request):
655+
return Response(status=status.HTTP_204_NO_CONTENT)
656+
657+
@action(detail=True, methods=['post', 'patch', 'delete'])
658+
def item_action(self, request, pk):
659+
return Response(status=status.HTTP_204_NO_CONTENT)
660+
661+
662+
class TestReadonlyModelViewSet(TestBase):
663+
"""
664+
Test if ReadOnlyModelViewSet allows to have custom actions with POST, PATCH, DELETE methods
665+
"""
666+
factory = RequestFactory()
667+
viewset_class = ReadOnlyViewSetWithCustomActions
668+
media_type = 'application/vnd.api+json'
669+
670+
def test_group_action_allows_post(self):
671+
view = self.viewset_class.as_view({'post': 'group_action'})
672+
request = self.factory.post('/', '{}', content_type=self.media_type)
673+
response = view(request)
674+
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
675+
676+
def test_group_action_allows_patch(self):
677+
view = self.viewset_class.as_view({'patch': 'group_action'})
678+
request = self.factory.patch('/', '{}', content_type=self.media_type)
679+
response = view(request)
680+
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
681+
682+
def test_group_action_allows_delete(self):
683+
view = self.viewset_class.as_view({'delete': 'group_action'})
684+
request = self.factory.delete('/', '{}', content_type=self.media_type)
685+
response = view(request)
686+
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
687+
688+
def test_item_action_allows_post(self):
689+
view = self.viewset_class.as_view({'post': 'item_action'})
690+
request = self.factory.post('/', '{}', content_type=self.media_type)
691+
response = view(request, pk='1')
692+
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
693+
694+
def test_item_action_allows_patch(self):
695+
view = self.viewset_class.as_view({'patch': 'item_action'})
696+
request = self.factory.patch('/', '{}', content_type=self.media_type)
697+
response = view(request, pk='1')
698+
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
699+
700+
def test_item_action_allows_delete(self):
701+
view = self.viewset_class.as_view({'delete': 'item_action'})
702+
request = self.factory.delete('/', '{}', content_type=self.media_type)
703+
response = view(request, pk='1')
704+
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)

‎rest_framework_json_api/views.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ class ModelViewSet(AutoPrefetchMixin,
210210
class ReadOnlyModelViewSet(AutoPrefetchMixin,
211211
RelatedMixin,
212212
viewsets.ReadOnlyModelViewSet):
213-
http_method_names = ['get', 'head', 'options']
213+
http_method_names = ['get', 'post', 'patch', 'delete', 'head', 'options']
214214

215215

216216
class RelationshipView(generics.GenericAPIView):

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /