From b51fd3f6a00e21e02d6e626c2cd4a665ac3d9c7e Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Thu, 4 Jul 2019 19:20:53 +0200
Subject: [PATCH] update: serialize object method

---
 djangoldp/serializers.py      | 37 ++++++++++++++++++++++++++++++++++-
 djangoldp/tests/models.py     | 12 +++++++++++-
 djangoldp/tests/tests_get.py  | 21 +++++++++++++++++++-
 djangoldp/tests/tests_temp.py |  6 +-----
 djangoldp/views.py            |  3 ++-
 5 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py
index 4e37dec9..b0450646 100644
--- a/djangoldp/serializers.py
+++ b/djangoldp/serializers.py
@@ -5,10 +5,11 @@ from urllib import parse
 from django.core.exceptions import ImproperlyConfigured
 from django.core.exceptions import ValidationError as DjangoValidationError
 from django.core.urlresolvers import get_resolver, resolve, get_script_prefix, Resolver404
+from django.db.models import QuerySet
 from django.utils.datastructures import MultiValueDictKeyError
 from django.utils.encoding import uri_to_iri
 from rest_framework.exceptions import ValidationError
-from rest_framework.fields import SkipField, empty
+from rest_framework.fields import SkipField, empty, ReadOnlyField
 from rest_framework.fields import get_error_detail, set_value
 from rest_framework.relations import HyperlinkedRelatedField, ManyRelatedField, MANY_RELATION_KWARGS, Hyperlink
 from rest_framework.serializers import HyperlinkedModelSerializer, ListSerializer, ModelSerializer
@@ -237,6 +238,40 @@ class LDPSerializer(HyperlinkedModelSerializer):
 
         return super().build_field(field_name, info, model_class, nested_depth)
 
+    def build_property_field(self, field_name, model_class):
+        class JSonLDPropertyField(ReadOnlyField):
+            def to_representation(self, instance):
+                if isinstance(instance, QuerySet):
+                    data = list(instance)
+                    model_class = instance.model
+                    from djangoldp.views import LDPViewSet
+
+                    serializer_generator = LDPViewSet(model=model_class,
+                                            lookup_field=Model.get_meta(model_class, 'lookup_field', 'pk'),
+                                            permission_classes=Model.get_meta(model_class, 'permission_classes', []),
+                                            fields=Model.get_meta(model_class, 'serializer_fields', []),
+                                            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)
+                    if parent_depth is 0:
+                        serializer.Meta.fields=["@id"]
+                    return {'@id': '',
+                            '@type': 'ldp:Container',
+                            'ldp:contains': [serializer.to_representation(item) if item is not None else None for item
+                                             in data],
+                            'permissions': Model.get_permissions(self.parent.Meta.model, self.context['request'].user,
+                                                                 ['view', 'add'])
+                            }
+                else:
+                    return instance
+
+        field_class = JSonLDPropertyField
+        field_kwargs = {}
+
+        return field_class, field_kwargs
+
     def build_standard_field(self, field_name, model_field):
         class JSonLDStandardField:
             parent_view_name = None
diff --git a/djangoldp/tests/models.py b/djangoldp/tests/models.py
index b23632ae..d0d16a23 100644
--- a/djangoldp/tests/models.py
+++ b/djangoldp/tests/models.py
@@ -1,6 +1,7 @@
 from django.conf import settings
 from django.contrib.auth import get_user_model
 from django.db import models
+from django.utils.datetime_safe import date
 
 from djangoldp.models import Model
 from djangoldp.permissions import AnonymousReadOnly
@@ -10,9 +11,13 @@ class Skill(Model):
     title = models.CharField(max_length=255, blank=True, null=True)
     obligatoire = models.CharField(max_length=255)
     slug = models.SlugField(blank=True, null=True, unique=True)
+    date = models.DateTimeField(auto_now_add=True, blank=True)
+
+    def recent_jobs(self):
+        return self.joboffer_set.filter(date__gte=date.today())
 
     class Meta:
-        serializer_fields = ["@id", "title"]
+        serializer_fields = ["@id", "title", "recent_jobs"]
         lookup_field = 'slug'
 
 
@@ -20,9 +25,14 @@ class JobOffer(Model):
     title = models.CharField(max_length=255, blank=True, null=True)
     skills = models.ManyToManyField(Skill, blank=True)
     slug = models.SlugField(blank=True, null=True, unique=True)
+    date = models.DateTimeField(auto_now_add=True, blank=True)
+
+    def recent_skills(self):
+        return self.skills.filter(date__gte=date.today())
 
     class Meta:
         nested_fields = ["skills"]
+        serializer_fields = ["@id", "title", "skills", "recent_skills"]
         container_path = "job-offers/"
         lookup_field = 'slug'
 
diff --git a/djangoldp/tests/tests_get.py b/djangoldp/tests/tests_get.py
index 9f5564d9..21c4b71e 100644
--- a/djangoldp/tests/tests_get.py
+++ b/djangoldp/tests/tests_get.py
@@ -3,7 +3,7 @@ import json
 from django.contrib.auth.models import User
 from rest_framework.test import APIRequestFactory, APIClient, APITestCase
 
-from djangoldp.tests.models import Post, Task, Invoice
+from djangoldp.tests.models import Post, Task, Invoice, JobOffer, Skill
 
 
 class TestGET(APITestCase):
@@ -40,3 +40,22 @@ class TestGET(APITestCase):
         response = self.client.get('/posts/', content_type='application/ld+json')
         self.assertEqual(response.status_code, 200)
 
+    def test_get_filtered_fields(self):
+        skill = Skill.objects.create(title="Java", obligatoire="ok", slug="1")
+        skill2 = Skill.objects.create(title="Java", obligatoire="ok", slug="2")
+        job = JobOffer.objects.create(title="job", slug="1")
+        job.skills.add(skill)
+        job.skills.add(skill2)
+        job.save()
+        response = self.client.get('/job-offers/{}/'.format(job.slug), content_type='application/ld+json')
+        self.assertEqual(response.status_code, 200)
+        self.assertIn('recent_skills', response.data)
+
+    def test_get_reverse_filtered_fields(self):
+        skill = Skill.objects.create(title="Java", obligatoire="ok", slug="1")
+        job = JobOffer.objects.create(title="job", slug="1")
+        job.skills.add(skill)
+        job.save()
+        response = self.client.get('/skills/{}/'.format(skill.slug), content_type='application/ld+json')
+        self.assertEqual(response.status_code, 200)
+        self.assertIn('recent_jobs', response.data)
diff --git a/djangoldp/tests/tests_temp.py b/djangoldp/tests/tests_temp.py
index 8a4b4d0f..578eb8a3 100644
--- a/djangoldp/tests/tests_temp.py
+++ b/djangoldp/tests/tests_temp.py
@@ -1,11 +1,7 @@
-from django.contrib.auth.models import User
 from django.test import TestCase
 from rest_framework.test import APIRequestFactory, APIClient
-from rest_framework.utils import json
 
-from djangoldp.serializers import LDPSerializer
-from djangoldp.tests.models import Post, UserProfile
-from djangoldp.tests.models import Skill, JobOffer, Conversation, Message
+from djangoldp.tests.models import Skill, JobOffer
 
 
 class TestTemp(TestCase):
diff --git a/djangoldp/views.py b/djangoldp/views.py
index 3d2b48b9..b20cd12c 100644
--- a/djangoldp/views.py
+++ b/djangoldp/views.py
@@ -15,7 +15,6 @@ from rest_framework.renderers import JSONRenderer
 from rest_framework.viewsets import ModelViewSet
 
 from djangoldp.models import LDPSource, Model
-from .serializers import LDPSerializer
 
 
 class JSONLDRenderer(JSONRenderer):
@@ -118,6 +117,7 @@ class LDPViewSet(LDPViewSetGenerator):
         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})
 
     def perform_create(self, serializer, **kwargs):
@@ -196,6 +196,7 @@ class LDPNestedViewSet(LDPViewSet):
             nested_related_name = related_field.remote_field.name
 
         return cls.urls(
+            lookup_field= Model.get_meta(related_field.related_model, 'lookup_field', 'pk'),
             model=related_field.related_model,
             exclude=(nested_related_name,) if related_field.one_to_many else (),
             parent_model=cls.get_model(**kwargs),
-- 
GitLab