Skip to content

Commit 55087bc

Browse files
authored
Convert ReadOnlyModelViewSet to pytest style (#1058)
1 parent 646d2a1 commit 55087bc

File tree

2 files changed

+40
-82
lines changed

2 files changed

+40
-82
lines changed

Diff for: example/tests/test_views.py

-81
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,11 @@
33

44
from django.test import RequestFactory, override_settings
55
from django.utils import timezone
6-
from rest_framework import status
7-
from rest_framework.decorators import action
86
from rest_framework.exceptions import NotFound
97
from rest_framework.request import Request
10-
from rest_framework.response import Response
118
from rest_framework.reverse import reverse
129
from rest_framework.test import APIRequestFactory, APITestCase, force_authenticate
1310

14-
from rest_framework_json_api import serializers, views
1511
from rest_framework_json_api.utils import format_resource_type
1612

1713
from example.factories import AuthorFactory, CommentFactory, EntryFactory
@@ -713,80 +709,3 @@ def test_get_object_gives_correct_entry(self):
713709
}
714710
got = resp.json()
715711
self.assertEqual(got, expected)
716-
717-
718-
class BasicAuthorSerializer(serializers.ModelSerializer):
719-
class Meta:
720-
model = Author
721-
fields = ("name",)
722-
723-
724-
class ReadOnlyViewSetWithCustomActions(views.ReadOnlyModelViewSet):
725-
queryset = Author.objects.all()
726-
serializer_class = BasicAuthorSerializer
727-
728-
@action(detail=False, methods=["get", "post", "patch", "delete"])
729-
def group_action(self, request):
730-
return Response(status=status.HTTP_204_NO_CONTENT)
731-
732-
@action(detail=True, methods=["get", "post", "patch", "delete"])
733-
def item_action(self, request, pk):
734-
return Response(status=status.HTTP_204_NO_CONTENT)
735-
736-
737-
class TestReadonlyModelViewSet(TestBase):
738-
"""
739-
Test if ReadOnlyModelViewSet allows to have custom actions with POST, PATCH, DELETE methods
740-
"""
741-
742-
factory = RequestFactory()
743-
viewset_class = ReadOnlyViewSetWithCustomActions
744-
media_type = "application/vnd.api+json"
745-
746-
def test_group_action_allows_get(self):
747-
view = self.viewset_class.as_view({"get": "group_action"})
748-
request = self.factory.get("/")
749-
response = view(request)
750-
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
751-
752-
def test_group_action_allows_post(self):
753-
view = self.viewset_class.as_view({"post": "group_action"})
754-
request = self.factory.post("/", "{}", content_type=self.media_type)
755-
response = view(request)
756-
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
757-
758-
def test_group_action_allows_patch(self):
759-
view = self.viewset_class.as_view({"patch": "group_action"})
760-
request = self.factory.patch("/", "{}", content_type=self.media_type)
761-
response = view(request)
762-
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
763-
764-
def test_group_action_allows_delete(self):
765-
view = self.viewset_class.as_view({"delete": "group_action"})
766-
request = self.factory.delete("/", "{}", content_type=self.media_type)
767-
response = view(request)
768-
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
769-
770-
def test_item_action_allows_get(self):
771-
view = self.viewset_class.as_view({"get": "item_action"})
772-
request = self.factory.get("/")
773-
response = view(request, pk="1")
774-
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
775-
776-
def test_item_action_allows_post(self):
777-
view = self.viewset_class.as_view({"post": "item_action"})
778-
request = self.factory.post("/", "{}", content_type=self.media_type)
779-
response = view(request, pk="1")
780-
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
781-
782-
def test_item_action_allows_patch(self):
783-
view = self.viewset_class.as_view({"patch": "item_action"})
784-
request = self.factory.patch("/", "{}", content_type=self.media_type)
785-
response = view(request, pk="1")
786-
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
787-
788-
def test_item_action_allows_delete(self):
789-
view = self.viewset_class.as_view({"delete": "item_action"})
790-
request = self.factory.delete("/", "{}", content_type=self.media_type)
791-
response = view(request, pk="1")
792-
self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)

Diff for: tests/test_views.py

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22
from django.urls import path, reverse
33
from rest_framework import status
4+
from rest_framework.decorators import action
45
from rest_framework.response import Response
56
from rest_framework.views import APIView
67

@@ -9,8 +10,9 @@
910
from rest_framework_json_api.relations import ResourceRelatedField
1011
from rest_framework_json_api.renderers import JSONRenderer
1112
from rest_framework_json_api.utils import format_link_segment
12-
from rest_framework_json_api.views import ModelViewSet
13+
from rest_framework_json_api.views import ModelViewSet, ReadOnlyModelViewSet
1314
from tests.models import BasicModel
15+
from tests.serializers import BasicModelSerializer
1416

1517

1618
class TestModelViewSet:
@@ -55,6 +57,43 @@ class RelatedFieldNameView(ModelViewSet):
5557
assert view.get_related_field_name() == related_model_field_name
5658

5759

60+
class TestReadonlyModelViewSet:
61+
@pytest.mark.parametrize(
62+
"method",
63+
["get", "post", "patch", "delete"],
64+
)
65+
@pytest.mark.parametrize(
66+
"custom_action,action_kwargs",
67+
[("list_action", {}), ("detail_action", {"pk": 1})],
68+
)
69+
def test_custom_action_allows_all_methods(
70+
self, rf, method, custom_action, action_kwargs
71+
):
72+
"""
73+
Test that write methods are allowed on custom list actions.
74+
75+
Even though a read only view only allows reading, custom actions
76+
should be allowed to define other methods which are allowed.
77+
"""
78+
79+
class ReadOnlyModelViewSetWithCustomActions(ReadOnlyModelViewSet):
80+
serializer_class = BasicModelSerializer
81+
queryset = BasicModel.objects.all()
82+
83+
@action(detail=False, methods=["get", "post", "patch", "delete"])
84+
def list_action(self, request):
85+
return Response(status=status.HTTP_204_NO_CONTENT)
86+
87+
@action(detail=True, methods=["get", "post", "patch", "delete"])
88+
def detail_action(self, request, pk):
89+
return Response(status=status.HTTP_204_NO_CONTENT)
90+
91+
view = ReadOnlyModelViewSetWithCustomActions.as_view({method: custom_action})
92+
request = getattr(rf, method)("/", data={})
93+
response = view(request, **action_kwargs)
94+
assert response.status_code == status.HTTP_204_NO_CONTENT
95+
96+
5897
class TestAPIView:
5998
@pytest.mark.urls(__name__)
6099
def test_patch(self, client):

0 commit comments

Comments
 (0)