Skip to content

Commit 610469d

Browse files
committed
Better handling of various HTTP methods for RelationshipView
1 parent 081d3a2 commit 610469d

File tree

1 file changed

+45
-6
lines changed

1 file changed

+45
-6
lines changed

rest_framework_json_api/views.py

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
from django.db.models.manager import BaseManager
33
from rest_framework import generics
44
from rest_framework.response import Response
5-
from rest_framework.exceptions import NotFound
5+
from rest_framework.exceptions import NotFound, MethodNotAllowed
66

7+
from rest_framework_json_api.exceptions import Conflict
78
from rest_framework_json_api.serializers import ResourceIdentifierObjectSerializer
89
from rest_framework_json_api.utils import format_relation_name, get_resource_type_from_instance
910

@@ -18,19 +19,57 @@ def get(self, request, *args, **kwargs):
1819

1920
def patch(self, request, *args, **kwargs):
2021
parent_obj = self.get_object()
21-
if hasattr(parent_obj, kwargs['related_field']):
22-
related_model_class = self.get_related_instance().__class__
22+
related_instance_or_manager = self.get_related_instance()
23+
24+
if isinstance(related_instance_or_manager, BaseManager):
25+
related_model_class = related_instance_or_manager.model
26+
serializer = self.get_serializer(data=request.data, model_class=related_model_class, many=True)
27+
serializer.is_valid(raise_exception=True)
28+
related_instance_or_manager.all().delete()
29+
related_instance_or_manager.add(*serializer.validated_data)
30+
else:
31+
related_model_class = related_instance_or_manager.__class__
2332
serializer = self.get_serializer(data=request.data, model_class=related_model_class)
2433
serializer.is_valid(raise_exception=True)
2534
setattr(parent_obj, kwargs['related_field'], serializer.validated_data)
2635
parent_obj.save()
27-
return Response(serializer.data)
36+
result_serializer = self._instantiate_serializer(related_instance_or_manager)
37+
return Response(result_serializer.data)
2838

2939
def post(self, request, *args, **kwargs):
30-
return Response()
40+
related_instance_or_manager = self.get_related_instance()
41+
42+
if isinstance(related_instance_or_manager, BaseManager):
43+
related_model_class = related_instance_or_manager.model
44+
serializer = self.get_serializer(data=request.data, model_class=related_model_class, many=True)
45+
serializer.is_valid(raise_exception=True)
46+
if frozenset(serializer.validated_data) <= frozenset(related_instance_or_manager.all()):
47+
return Response(status=204)
48+
related_instance_or_manager.add(*serializer.validated_data)
49+
else:
50+
raise MethodNotAllowed('POST')
51+
result_serializer = self._instantiate_serializer(related_instance_or_manager)
52+
return Response(result_serializer.data)
3153

3254
def delete(self, request, *args, **kwargs):
33-
return Response()
55+
related_instance_or_manager = self.get_related_instance()
56+
57+
if isinstance(related_instance_or_manager, BaseManager):
58+
related_model_class = related_instance_or_manager.model
59+
serializer = self.get_serializer(data=request.data, model_class=related_model_class, many=True)
60+
serializer.is_valid(raise_exception=True)
61+
if frozenset(serializer.validated_data).isdisjoint(frozenset(related_instance_or_manager.all())):
62+
return Response(status=204)
63+
try:
64+
related_instance_or_manager.remove(*serializer.validated_data)
65+
except AttributeError:
66+
raise Conflict(
67+
'This object cannot be removed from this relationship without being added to another'
68+
)
69+
else:
70+
raise MethodNotAllowed('DELETE')
71+
result_serializer = self._instantiate_serializer(related_instance_or_manager)
72+
return Response(result_serializer.data)
3473

3574
def get_related_instance(self):
3675
try:

0 commit comments

Comments
 (0)