diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 0539e862543ccfe587c04e814831eb12b605015d..68ea4827c49c7df8853c371ef0735e6b8e4ef8de 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -432,23 +432,9 @@ class LDPSerializer(HyperlinkedModelSerializer): for field_name in nested_fields_name: nested_fields.append((field_name, validated_data.pop(field_name))) - info = model_meta.get_field_info(instance) for attr, value in validated_data.items(): if isinstance(value, dict): - slug_field = Model.slug_field(instance) - relation_info = info.relations.get(attr) - if slug_field in value: - kwargs = {slug_field: value[slug_field]} - if relation_info.to_many: - manager = getattr(instance, attr) - oldObj = manager._meta.model.objects.get(**kwargs) - else: - oldObj = getattr(instance, attr) - value = self.update(instance=oldObj, validated_data=value) - else: - if not relation_info.to_many: - value[instance._meta.fields_map[attr].remote_field.name] = instance - value = self.internal_create(validated_data=value, model=relation_info.related_model) + value = self.update_dict_value(attr, instance, value) setattr(instance, attr, value) instance.save() @@ -457,6 +443,39 @@ class LDPSerializer(HyperlinkedModelSerializer): return instance + def update_dict_value(self, attr, instance, value): + info = model_meta.get_field_info(instance) + slug_field = Model.slug_field(instance) + relation_info = info.relations.get(attr) + if slug_field in value: + value = self.update_dict_value_when_id_is_provided(attr, instance, relation_info, slug_field, value) + else: + value = self.update_dict_value_without_slug_field(attr, instance, relation_info, value) + return value + + def update_dict_value_without_slug_field(self, attr, instance, relation_info, value): + if relation_info.to_many: + value = self.internal_create(validated_data=value, model=relation_info.related_model) + else: + value[instance._meta.fields_map[attr].remote_field.name] = instance + oldObj = getattr(instance, attr, None) + if oldObj is None: + value = self.internal_create(validated_data=value, model=relation_info.related_model) + else: + value = self.update(instance=oldObj, validated_data=value) + return value + + def update_dict_value_when_id_is_provided(self, attr, instance, relation_info, slug_field, value): + kwargs = {slug_field: value[slug_field]} + if relation_info.to_many: + manager = getattr(instance, attr) + oldObj = manager._meta.model.objects.get(**kwargs) + else: + oldObj = getattr(instance, attr) + + value = self.update(instance=oldObj, validated_data=value) + return value + def save_or_update_nested_list(self, instance, nested_fields): for (field_name, data) in nested_fields: manager = getattr(instance, field_name) diff --git a/djangoldp/tests/models.py b/djangoldp/tests/models.py index 899a123272a72ad4c9cd8a6f3e334717d91330e9..b461d90d3ac1bdbbd19e82ccf194bb32a192ccda 100644 --- a/djangoldp/tests/models.py +++ b/djangoldp/tests/models.py @@ -89,4 +89,4 @@ class Post(Model): auto_author = 'author' -get_user_model()._meta.serializer_fields = ['@id', 'username', 'first_name', 'last_name', 'email', 'userprofile'] \ No newline at end of file +get_user_model()._meta.serializer_fields = ['@id', 'username', 'first_name', 'last_name', 'email', 'userprofile', 'conversation_set'] \ No newline at end of file diff --git a/djangoldp/tests/tests_update.py b/djangoldp/tests/tests_update.py index 5ba048c200d8a4822c5ff1c9094172e9319accfe..6f1e677d1578a00f202b32397812285f7c23871f 100644 --- a/djangoldp/tests/tests_update.py +++ b/djangoldp/tests/tests_update.py @@ -4,7 +4,7 @@ from rest_framework.test import APIRequestFactory, APIClient from rest_framework.utils import json from djangoldp.serializers import LDPSerializer -from djangoldp.tests.models import Post +from djangoldp.tests.models import Post, UserProfile from djangoldp.tests.models import Skill, JobOffer, Conversation, Message @@ -272,8 +272,7 @@ class Update(TestCase): self.assertEquals(response.data['content'], "post content") self.assertIn('location', response._headers) - - def test_create_sub_object_in_existing_object_with_reverse_relation(self): + def test_create_sub_object_in_existing_object_with_reverse_1to1_relation(self): """ Doesn't work with depth = 0 on UserProfile Model. Should it be ? """ @@ -281,7 +280,7 @@ class Update(TestCase): body = [ { '@id': "_:b975", - 'http://happy-dev.fr/owl/#description': "conversation description" + 'http://happy-dev.fr/owl/#description': "user description" }, { '@id': '/users/{}/'.format(user.pk), @@ -295,3 +294,68 @@ class Update(TestCase): content_type='application/ld+json') self.assertEqual(response.status_code, 200) self.assertIn('userprofile', response.data) + + def test_create_sub_object_in_existing_object_with_existing_reverse_1to1_relation(self): + user = User.objects.create(username="alex", password="test") + profile = UserProfile.objects.create(user=user, description="user description") + body = [ + { + '@id': "/userprofiles/{}/".format(profile.pk), + 'http://happy-dev.fr/owl/#description': "user update" + }, + { + '@id': '/users/{}/'.format(user.pk), + "http://happy-dev.fr/owl/#first_name": "Alexandre", + "http://happy-dev.fr/owl/#last_name": "Bourlier", + "http://happy-dev.fr/owl/#username": "alex", + 'http://happy-dev.fr/owl/#userprofile': {'@id': "/userprofiles/{}/".format(profile.pk)} + } + ] + response = self.client.put('/users/{}/'.format(user.pk), data=json.dumps(body), + content_type='application/ld+json') + self.assertEqual(response.status_code, 200) + self.assertIn('userprofile', response.data) + + def test_create_sub_object_in_existing_object_with_reverse_fk_relation(self): + """ + Doesn't work with depth = 0 on UserProfile Model. Should it be ? + """ + user = User.objects.create(username="alex", password="test") + body = [ + { + '@id': "_:b975", + 'http://happy-dev.fr/owl/#description': "conversation description" + }, + { + '@id': '/users/{}/'.format(user.pk), + "http://happy-dev.fr/owl/#first_name": "Alexandre", + "http://happy-dev.fr/owl/#last_name": "Bourlier", + "http://happy-dev.fr/owl/#username": "alex", + 'http://happy-dev.fr/owl/#conversation_set': {'@id': "_:b975"} + } + ] + response = self.client.put('/users/{}/'.format(user.pk), data=json.dumps(body), + content_type='application/ld+json') + self.assertEqual(response.status_code, 200) + self.assertIn('conversation_set', response.data) + + def test_create_sub_object_in_existing_object_with_existing_reverse_fk_relation(self): + user = User.objects.create(username="alex", password="test") + conversation = Conversation.objects.create(author_user=user, description="conversation description") + body = [ + { + '@id': "/conversations/{}/".format(conversation.pk), + 'http://happy-dev.fr/owl/#description': "conversation update" + }, + { + '@id': '/users/{}/'.format(user.pk), + "http://happy-dev.fr/owl/#first_name": "Alexandre", + "http://happy-dev.fr/owl/#last_name": "Bourlier", + "http://happy-dev.fr/owl/#username": "alex", + 'http://happy-dev.fr/owl/#conversation_set': {'@id': "/conversations/{}/".format(conversation.pk)} + } + ] + response = self.client.put('/users/{}/'.format(user.pk), data=json.dumps(body), + content_type='application/ld+json') + self.assertEqual(response.status_code, 200) + self.assertIn('conversation_set', response.data) \ No newline at end of file