diff --git a/djangoldp/__init__.py b/djangoldp/__init__.py index 5c4fa333d4cb80499002f6da50e1731faca9ac7d..e34d4cff350ca58512df3cc619e1cc6921252569 100644 --- a/djangoldp/__init__.py +++ b/djangoldp/__init__.py @@ -1,4 +1,4 @@ from django.db.models import options __version__ = '0.0.0' -options.DEFAULT_NAMES += ('lookup_field', 'rdf_type', 'rdf_context', 'auto_author', 'view_set', 'container_path', 'permission_classes', 'serializer_fields', 'nested_fields', 'depth', 'many_depth', 'anonymous_perms', 'authenticated_perms', 'owner_perms') \ No newline at end of file +options.DEFAULT_NAMES += ('lookup_field', 'rdf_type', 'rdf_context', 'auto_author', 'view_set', 'container_path', 'permission_classes', 'serializer_fields', 'nested_fields', 'depth', 'anonymous_perms', 'authenticated_perms', 'owner_perms') diff --git a/djangoldp/models.py b/djangoldp/models.py index f091a037248b5beadd3e6b6c4d1359668597779e..477d8d942b26888d3a67f50722ea0d57a95d406e 100644 --- a/djangoldp/models.py +++ b/djangoldp/models.py @@ -66,8 +66,7 @@ class Model(models.Model): class Meta: default_permissions = ('add', 'change', 'delete', 'view', 'control') abstract = True - depth = 1 - many_depth = 0 + depth = 0 @classonlymethod def resolve_id(cls, id): diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 4412e88036155374c80229c5e3148330ce6b52b6..06b38daad1f3c21a5b72e312f322631f2ff9ae2a 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -239,8 +239,6 @@ class LDPSerializer(HyperlinkedModelSerializer): return data def build_field(self, field_name, info, model_class, nested_depth): - nested_depth = self.compute_depth(nested_depth, model_class) - return super().build_field(field_name, info, model_class, nested_depth) def build_property_field(self, field_name, model_class): @@ -259,8 +257,7 @@ class LDPSerializer(HyperlinkedModelSerializer): nested_fields=Model.get_meta(model_class, 'nested_fields', [])) parent_depth = max(getattr(self.parent.Meta, "depth", 0) - 1, 0) serializer_generator.depth = parent_depth - serializer_generator.many_depth = max(getattr(self.parent.Meta, "many_depth", 0) - 1, 0) - serializer = serializer_generator.build_serializer()(context=self.parent.context) + serializer = serializer_generator.build_read_serializer()(context=self.parent.context) if parent_depth is 0: serializer.Meta.fields = ["@id"] return {'@id': '{}{}{}/'.format(settings.SITE_URL, '{}{}/', self.source), @@ -320,7 +317,6 @@ class LDPSerializer(HyperlinkedModelSerializer): return type(field_class.__name__ + 'Valued', (JSonLDStandardField, field_class), {}), field_kwargs def build_nested_field(self, field_name, relation_info, nested_depth): - nested_depth = self.compute_depth(nested_depth, self.Meta.model) class NestedLDPSerializer(self.__class__): @@ -392,23 +388,10 @@ class LDPSerializer(HyperlinkedModelSerializer): kwargs['required'] = False return NestedLDPSerializer, kwargs - @classmethod - def compute_depth(cls, depth, model_class, name='depth'): - try: - model_depth = getattr(model_class._meta, 'depth', getattr(model_class.Meta, 'depth', 10)) - depth = min(depth, int(model_depth)) - except AttributeError: - depth = min(depth, int(getattr(model_class._meta, 'depth', 1))) - - return depth @classmethod def many_init(cls, *args, **kwargs): kwargs['child'] = cls(**kwargs) - try: - cls.Meta.depth = cls.compute_depth(kwargs['context']['view'].many_depth, cls.Meta.model, 'many_depth') - except KeyError: - pass return ContainerSerializer(*args, **kwargs) def get_value(self, dictionary): diff --git a/djangoldp/tests/tests_update.py b/djangoldp/tests/tests_update.py index c14589889694f5b719e5e5019200885c677977c8..292b0bafbb1ad3b8c17abd7e4b4e189b9a5c8dfc 100644 --- a/djangoldp/tests/tests_update.py +++ b/djangoldp/tests/tests_update.py @@ -281,8 +281,8 @@ class Update(TestCase): { '@id': "_:b975", 'http://happy-dev.fr/owl/#description': "user description", - 'http://happy-dev.fr/owl/#dummy': { - '@id' : './' + 'http://happy-dev.fr/owl/#dummy': { + '@id': './' } }, { @@ -366,7 +366,8 @@ class Update(TestCase): def test_missing_field_should_not_be_removed_with_fk_relation(self): user = User.objects.create(username="alex", password="test") peer = User.objects.create(username="sylvain", password="test2") - conversation = Conversation.objects.create(author_user=user, peer_user=peer, description="conversation description") + conversation = Conversation.objects.create(author_user=user, peer_user=peer, + description="conversation description") body = [ { '@id': "/conversations/{}/".format(conversation.pk), @@ -381,7 +382,8 @@ class Update(TestCase): def test_empty_field_should_be_removed_with_fk_relation(self): user = User.objects.create(username="alex", password="test") peer = User.objects.create(username="sylvain", password="test2") - conversation = Conversation.objects.create(author_user=user, peer_user=peer, description="conversation description") + conversation = Conversation.objects.create(author_user=user, peer_user=peer, + description="conversation description") body = [ { '@id': "/conversations/{}/".format(conversation.pk), @@ -393,4 +395,3 @@ class Update(TestCase): content_type='application/ld+json') self.assertEqual(response.status_code, 200) self.assertEqual(response.data['peer_user'], None) - diff --git a/djangoldp/views.py b/djangoldp/views.py index 6b2ecc5e953d287a2523449964281e1c56356e1b..addeb0ff552be2bf6fa116222e06eadd63b62aa4 100644 --- a/djangoldp/views.py +++ b/djangoldp/views.py @@ -9,10 +9,13 @@ from django.shortcuts import get_object_or_404 from django.utils.decorators import classonlymethod from guardian.shortcuts import get_objects_for_user from pyld import jsonld +from rest_framework import status from rest_framework.authentication import SessionAuthentication from rest_framework.parsers import JSONParser from rest_framework.renderers import JSONRenderer from rest_framework.viewsets import ModelViewSet +from rest_framework.response import Response + from djangoldp.models import LDPSource, Model from djangoldp.permissions import LDPPermissions @@ -91,8 +94,7 @@ class LDPViewSet(LDPViewSetGenerator): """An automatically generated viewset that serves models following the Linked Data Platform convention""" fields = None exclude = None - depth = 2 - many_depth = 1 + depth = 1 renderer_classes = (JSONLDRenderer,) parser_classes = (JSONLDParser,) authentication_classes = (NoCSRFAuthentication,) @@ -104,22 +106,69 @@ class LDPViewSet(LDPViewSetGenerator): if hasattr(p, 'filter_class') and p.filter_class: self.filter_backends = p.filter_class - self.serializer_class = self.build_serializer() + self.serializer_class = self.build_read_serializer() + self.write_serializer_class = self.build_write_serializer() - def build_serializer(self): + def build_read_serializer(self): model_name = self.model._meta.object_name.lower() lookup_field = get_resolver().reverse_dict[model_name + '-detail'][0][0][1][0] meta_args = {'model': self.model, 'extra_kwargs': { '@id': {'lookup_field': lookup_field}}, 'depth': self.depth, 'extra_fields': self.nested_fields} + return self.build_serializer(meta_args, 'Read') + + def build_write_serializer(self): + model_name = self.model._meta.object_name.lower() + lookup_field = get_resolver().reverse_dict[model_name + '-detail'][0][0][1][0] + meta_args = {'model': self.model, 'extra_kwargs': { + '@id': {'lookup_field': lookup_field}}, + 'depth': 10, + 'extra_fields': self.nested_fields} + return self.build_serializer(meta_args, 'Write') + + def build_serializer(self, meta_args, name_prefix): if self.fields: meta_args['fields'] = self.fields else: meta_args['exclude'] = self.exclude or () meta_class = type('Meta', (), meta_args) from djangoldp.serializers import LDPSerializer - return type(LDPSerializer)(model_name + 'Serializer', (LDPSerializer,), {'Meta': meta_class}) + return type(LDPSerializer)(self.model._meta.object_name.lower() + name_prefix + 'Serializer', (LDPSerializer,), {'Meta': meta_class}) + + def create(self, request, *args, **kwargs): + serializer = self.get_write_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + + def get_write_serializer(self, *args, **kwargs): + """ + Return the serializer instance that should be used for validating and + deserializing input, and for serializing output. + """ + serializer_class = self.get_write_serializer_class() + kwargs['context'] = self.get_serializer_context() + return serializer_class(*args, **kwargs) + + def get_write_serializer_class(self): + """ + Return the class to use for the serializer. + Defaults to using `self.write_serializer_class`. + + You may want to override this if you need to provide different + serializations depending on the incoming request. + + (Eg. admins get full serialization, others get basic serialization) + """ + assert self.write_serializer_class is not None, ( + "'%s' should either include a `write_serializer_class` attribute, " + "or override the `get_write_serializer_class()` method." + % self.__class__.__name__ + ) + + return self.write_serializer_class def perform_create(self, serializer, **kwargs): if hasattr(self.model._meta, 'auto_author') and isinstance(self.request.user, get_user_model()):