Skip to content

Avoid patch on RelationshipView deleting relationship instance when constraint would allow null #499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 25, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ any parts of the framework not mentioned in the documentation should generally b
### Fixed

* Pass context from `PolymorphicModelSerializer` to child serializers to support fields which require a `request` context such as `url`.
* Avoid patch on `RelationshipView` deleting relationship instance when constraint would allow null ([#242](https://github.com/django-json-api/django-rest-framework-json-api/issues/242))


## [2.6.0] - 2018-09-20
46 changes: 45 additions & 1 deletion example/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@

from . import TestBase
from .. import views
from example.factories import AuthorFactory, EntryFactory
from example.factories import AuthorFactory, CommentFactory, EntryFactory
from example.models import Author, Blog, Comment, Entry
from example.serializers import AuthorBioSerializer, AuthorTypeSerializer, EntrySerializer
from example.views import AuthorViewSet
@@ -229,6 +229,50 @@ def test_delete_to_many_relationship_with_change(self):
response = self.client.delete(url, data=request_data)
assert response.status_code == 200, response.content.decode()

def test_new_comment_data_patch_to_many_relationship(self):
entry = EntryFactory(blog=self.blog, authors=(self.author,))
comment = CommentFactory(entry=entry)

url = '/authors/{}/relationships/comment_set'.format(self.author.id)
request_data = {
'data': [{'type': format_resource_type('Comment'), 'id': str(comment.id)}, ]
}
previous_response = {
'data': [
{'type': 'comments',
'id': str(self.second_comment.id)
}
],
'links': {
'self': 'http://testserver/authors/{}/relationships/comment_set'.format(
self.author.id
)
}
}

response = self.client.get(url)
assert response.status_code == 200
assert response.json() == previous_response

new_patched_response = {
'data': [
{'type': 'comments',
'id': str(comment.id)
}
],
'links': {
'self': 'http://testserver/authors/{}/relationships/comment_set'.format(
self.author.id
)
}
}

response = self.client.patch(url, data=request_data)
assert response.status_code == 200
assert response.json() == new_patched_response

assert Comment.objects.filter(id=self.second_comment.id).exists()


class TestRelatedMixin(APITestCase):

23 changes: 22 additions & 1 deletion rest_framework_json_api/views.py
Original file line number Diff line number Diff line change
@@ -251,6 +251,18 @@ def get(self, request, *args, **kwargs):
serializer_instance = self._instantiate_serializer(related_instance)
return Response(serializer_instance.data)

def remove_relationships(self, instance_manager, field):
field_object = getattr(instance_manager, field)

if field_object.null:
for obj in instance_manager.all():
setattr(obj, field_object.name, None)
obj.save()
else:
instance_manager.all().delete()

return instance_manager

def patch(self, request, *args, **kwargs):
parent_obj = self.get_object()
related_instance_or_manager = self.get_related_instance()
@@ -261,7 +273,16 @@ def patch(self, request, *args, **kwargs):
data=request.data, model_class=related_model_class, many=True
)
serializer.is_valid(raise_exception=True)
related_instance_or_manager.all().delete()

# for to one
if hasattr(related_instance_or_manager, "field"):
related_instance_or_manager = self.remove_relationships(
instance_manager=related_instance_or_manager, field="field")
# for to many
else:
related_instance_or_manager = self.remove_relationships(
instance_manager=related_instance_or_manager, field="target_field")

# have to set bulk to False since data isn't saved yet
class_name = related_instance_or_manager.__class__.__name__
if class_name != 'ManyRelatedManager':