diff --git a/djangoldp/models.py b/djangoldp/models.py index e66c1170247a2b653fc5d3957c0415e092f67057..ecb4027ad688d1604e937d735681455128b817ae 100644 --- a/djangoldp/models.py +++ b/djangoldp/models.py @@ -1,6 +1,7 @@ from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.db import models +from django.db.models.base import ModelBase from django.urls import get_resolver from django.utils.decorators import classonlymethod from guardian.shortcuts import get_perms @@ -36,8 +37,12 @@ class Model(models.Model): return cls.__clean_path(r_id) @classonlymethod - def slug_field(cls, instance): - view_name = '{}-detail'.format(instance._meta.object_name.lower()) + def slug_field(cls, instance_or_model): + if isinstance(instance_or_model, ModelBase): + object_name = instance_or_model.__name__.lower() + else: + object_name = instance_or_model._meta.object_name.lower() + view_name = '{}-detail'.format(object_name) slug_field = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][1][0]) if slug_field.startswith('/'): slug_field = slug_field[1:] @@ -113,7 +118,6 @@ class Model(models.Model): return [{'mode': {'@type': name.split('_')[0]}} for name in permissions] - class LDPSource(models.Model): container = models.URLField() federation = models.CharField(max_length=255) diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 3b0f101f70e0a5c83d3ea22454d187b1a6862e44..bf364e6eecf77d77e7415ae9dae2e226cb9eab56 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -358,7 +358,7 @@ class LDPSerializer(HyperlinkedModelSerializer): if item is empty: return empty try: - full_item = next(filter(lambda o: item[self.url_field_name] == o[self.url_field_name], object_list)) + full_item = next(filter(lambda o: self.url_field_name in o and (item[self.url_field_name] == o[self.url_field_name]), object_list)) except StopIteration: pass if full_item is None: @@ -390,10 +390,20 @@ class LDPSerializer(HyperlinkedModelSerializer): getattr(instance, field_name).add(related) def internal_create(self, validated_data, model): - nested_fields = [] + nested_fk_fields_name = list(filter(lambda key: isinstance(validated_data[key], dict), validated_data)) - # TODO replace fk_fields_name by the instance in validated_data + for field_name in nested_fk_fields_name: + field_dict = validated_data[field_name] + field_model = getattr(model, field_name).field.rel.model + slug_field = Model.slug_field(field_model) + if slug_field in field_dict: + kwargs = {slug_field: field_dict[slug_field]} + sub_inst = field_model.objects.get(**kwargs) + else: + sub_inst = self.internal_create(field_dict, field_model ) + validated_data[field_name] = sub_inst + nested_fields = [] nested_list_fields_name = list(filter(lambda key: isinstance(validated_data[key], list), validated_data)) for field_name in nested_list_fields_name: nested_fields.append((field_name, validated_data.pop(field_name))) diff --git a/djangoldp/tests/models.py b/djangoldp/tests/models.py index 9f8286671bc0310a1a629ab7fe01022284ae1240..d515cc05da8f91830a2d62a2004a245236216de5 100644 --- a/djangoldp/tests/models.py +++ b/djangoldp/tests/models.py @@ -61,7 +61,7 @@ class Batch(Model): class Meta: serializer_fields = ['@id', 'title', 'invoice', 'tasks'] - nested_fields = ["tasks"] + nested_fields = ["tasks", 'invoice'] class Task(models.Model): diff --git a/djangoldp/tests/runner.py b/djangoldp/tests/runner.py index dcb50a99173589b1ae388f7242e8df50d9c215db..52ea84883145ef69aa1a8a8edc501f59abde6349 100644 --- a/djangoldp/tests/runner.py +++ b/djangoldp/tests/runner.py @@ -53,14 +53,14 @@ from django.test.runner import DiscoverRunner test_runner = DiscoverRunner(verbosity=1) failures = test_runner.run_tests([ - # 'djangoldp.tests.tests_ldp_model', - # 'djangoldp.tests.tests_save', - # 'djangoldp.tests.tests_user_permissions', - # 'djangoldp.tests.tests_anonymous_permissions', - # 'djangoldp.tests.tests_update', - # 'djangoldp.tests.tests_auto_author', - 'djangoldp.tests.tests_temp' - # 'djangoldp.tests.tests_get' + 'djangoldp.tests.tests_ldp_model', + 'djangoldp.tests.tests_save', + 'djangoldp.tests.tests_user_permissions', + 'djangoldp.tests.tests_anonymous_permissions', + 'djangoldp.tests.tests_update', + 'djangoldp.tests.tests_auto_author', + # 'djangoldp.tests.tests_temp' + 'djangoldp.tests.tests_get' ]) if failures: sys.exit(failures) diff --git a/djangoldp/tests/tests_save.py b/djangoldp/tests/tests_save.py index a0926a2ce4f2e0accd2fe6eaa1d23263c89f59ea..3b63d44a75920eb997fadcc1b05dba63385376b5 100644 --- a/djangoldp/tests/tests_save.py +++ b/djangoldp/tests/tests_save.py @@ -1,5 +1,7 @@ from django.test import TestCase +from rest_framework.utils import json +from djangoldp.models import Model from djangoldp.serializers import LDPSerializer from djangoldp.tests.models import Skill, JobOffer, Invoice, Message @@ -146,24 +148,42 @@ class Save(TestCase): self.assertIs(result.joboffer_set.get().skills.count(), 1) def test_save_fk_graph_with_nested(self): - skill1 = Skill.objects.create(title="skill1", obligatoire="obligatoire") - skill2 = Skill.objects.create(title="skill2", obligatoire="obligatoire") - - message = {"@graph": [ - {"text": "message test", - "thread": {"@id": "_.123"} - }, - {"@id": "_.123", "description": "thread"}, - ]} + post = { + '@graph': [ + { + 'http://happy-dev.fr/owl/#title': "title", + 'http://happy-dev.fr/owl/#invoice': { + '@id': "_.123" + } + }, + { + '@id': "_.123", + 'http://happy-dev.fr/owl/#title': "title 2" + } + ] + } - meta_args = {'model': Message, 'depth': 2, 'fields': ("@id", "text", "thread")} + response = self.client.post('/batchs/', data=json.dumps(post), content_type='application/ld+json') + self.assertEqual(response.status_code, 201) + self.assertNotIn('author', response.data) + self.assertEquals(response.data['title'], "title") + self.assertEquals(response.data['invoice']['title'], "title 2") - meta_class = type('Meta', (), meta_args) - serializer_class = type(LDPSerializer)('MessageSerializer', (LDPSerializer,), {'Meta': meta_class}) - serializer = serializer_class(data=message) - serializer.is_valid() - result = serializer.save() + def test_save_fk_graph_with_existing_nested(self): + invoice = Invoice.objects.create(title="title 3") + post = { + '@graph': [ + { + 'http://happy-dev.fr/owl/#title': "title", + 'http://happy-dev.fr/owl/#invoice': { + '@id': "https://happy-dev.fr{}{}/".format(Model.container_id(invoice), invoice.id) + } + } + ] + } - self.assertEquals(result.text, "message test") - self.assertIsNotNone(result.thread) - self.assertEquals(result.thread.description, "thread") + response = self.client.post('/batchs/', data=json.dumps(post), content_type='application/ld+json') + self.assertEqual(response.status_code, 201) + self.assertNotIn('author', response.data) + self.assertEquals(response.data['title'], "title") + self.assertEquals(response.data['invoice']['title'], "title 3") diff --git a/djangoldp/tests/tests_temp.py b/djangoldp/tests/tests_temp.py new file mode 100644 index 0000000000000000000000000000000000000000..309931fde07780b008cb4fd6da10950028944d13 --- /dev/null +++ b/djangoldp/tests/tests_temp.py @@ -0,0 +1,11 @@ +import json + +from rest_framework.test import APITestCase + +from djangoldp.models import Model +from djangoldp.tests.models import Invoice + + +class TestTemp(APITestCase): + pass + diff --git a/djangoldp/tests/urls.py b/djangoldp/tests/urls.py index 7ac1c38f725a1f83c50bc1393bc37c28259f43b1..a686bd1b7aa76e48fed6e1db9a86480507bed55e 100644 --- a/djangoldp/tests/urls.py +++ b/djangoldp/tests/urls.py @@ -5,7 +5,7 @@ from djangoldp.tests.models import Skill, JobOffer, Message, Thread, Dummy from djangoldp.views import LDPViewSet urlpatterns = [ - url(r'^messages/', LDPViewSet.urls(model=Message, permission_classes=[], fields=["@id", "text"], nested_fields=[])), + url(r'^messages/', LDPViewSet.urls(model=Message, permission_classes=[], fields=["@id", "text", "thread"], nested_fields=['thread'])), url(r'^threads/', LDPViewSet.urls(model=Thread, nested_fields=["message_set"], permission_classes=())), url(r'^users/', LDPViewSet.urls(model=settings.AUTH_USER_MODEL, permission_classes=[])), url(r'^dummys/', LDPViewSet.urls(model=Dummy, permission_classes=[], lookup_field='slug',)), diff --git a/setup.cfg b/setup.cfg index 70a69cd1576a2714ed284e74473220cea19671ea..bc9625e0db96d83f38ded90c8a746a33733ae6de 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,6 +14,7 @@ setup_requires = install_requires = django~=1.11 django_rest_framework + requests pyld django-guardian