From dd4447d7b8955e627cba88909ebc59fffd19c441 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 19 Feb 2019 15:38:27 +0100
Subject: [PATCH 1/8] update: add failing tests for urls resolver feature

---
 djangoldp/models.py               | 13 +++++++++++++
 djangoldp/resolver.py             | 17 +++++++++++++++++
 djangoldp/tests/models.py         | 10 ++++++++++
 djangoldp/tests/runner.py         |  1 +
 djangoldp/tests/tests_resolver.py | 25 +++++++++++++++++++++++++
 djangoldp/tests/tests_save.py     |  2 +-
 djangoldp/tests/tests_update.py   |  2 +-
 djangoldp/tests/urls.py           |  3 ++-
 8 files changed, 70 insertions(+), 3 deletions(-)
 create mode 100644 djangoldp/resolver.py
 create mode 100644 djangoldp/tests/tests_resolver.py

diff --git a/djangoldp/models.py b/djangoldp/models.py
index 50b31c6c..bcb62f61 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -1,6 +1,19 @@
 from django.conf import settings
 from django.db import models
 
+
+class LDPModel(models.Model):
+    ldp_path = None
+
+    def full_path(self):
+        return "{}/{}".format(self.container_path(), self.pk)
+
+    def container_path(self):
+        return self.ldp_path
+
+    class Meta:
+        abstract = True
+
 class LDPSource(models.Model):
     container = models.URLField()
     federation = models.CharField(max_length=255)
diff --git a/djangoldp/resolver.py b/djangoldp/resolver.py
new file mode 100644
index 00000000..949ae3f1
--- /dev/null
+++ b/djangoldp/resolver.py
@@ -0,0 +1,17 @@
+class LDPResolver:
+
+    @classmethod
+    def resource_url(cls, dummy):
+        pass
+
+    @classmethod
+    def container_url(cls, dummy):
+        pass
+
+    @classmethod
+    def resource_path(cls, dummy):
+        pass
+
+    @classmethod
+    def container_path(cls, dummy):
+        pass
diff --git a/djangoldp/tests/models.py b/djangoldp/tests/models.py
index 13a0aedf..29b0a521 100644
--- a/djangoldp/tests/models.py
+++ b/djangoldp/tests/models.py
@@ -1,6 +1,8 @@
 from django.conf import settings
 from django.db import models
 
+from djangoldp.models import LDPModel
+
 
 class Skill(models.Model):
     title = models.CharField(max_length=255, blank=True, null=True)
@@ -23,3 +25,11 @@ class Message(models.Model):
     author_user = models.ForeignKey(settings.AUTH_USER_MODEL)
 
 
+class Dummy(models.Model):
+    some = models.CharField(max_length=255, blank=True, null=True)
+
+
+class LDPDummy(LDPModel):
+    some = models.CharField(max_length=255, blank=True, null=True)
+    ldp_path = "ldp-dummys"
+
diff --git a/djangoldp/tests/runner.py b/djangoldp/tests/runner.py
index 1cf8604d..17419667 100644
--- a/djangoldp/tests/runner.py
+++ b/djangoldp/tests/runner.py
@@ -25,6 +25,7 @@ from django.test.runner import DiscoverRunner
 test_runner = DiscoverRunner(verbosity=1)
 
 failures = test_runner.run_tests([
+    'djangoldp.tests.tests_resolver',
     'djangoldp.tests.tests_save',
     'djangoldp.tests.tests_update'])
 if failures:
diff --git a/djangoldp/tests/tests_resolver.py b/djangoldp/tests/tests_resolver.py
new file mode 100644
index 00000000..55818f6d
--- /dev/null
+++ b/djangoldp/tests/tests_resolver.py
@@ -0,0 +1,25 @@
+from django.test import TestCase
+
+from djangoldp.resolver import LDPResolver
+from djangoldp.tests.models import Dummy, LDPDummy
+
+
+class UrlUtils(TestCase):
+
+    def test_class_not_inheriting_ldp_model(self):
+        dummy = Dummy.objects.create(some="text")
+        self.assertEquals("http://localhost/dummys/{}".format(dummy.pk), LDPResolver.resource_url(dummy))
+        self.assertEquals("/dummys/{}".format(dummy.pk), LDPResolver.resource_path(dummy))
+        self.assertEquals("http://localhost/dummys", LDPResolver.container_url(dummy))
+        self.assertEquals("/dummys", LDPResolver.container_path(dummy))
+
+    def test_class_inheriting_ldp_model(self):
+        dummy = LDPDummy.objects.create(some="text")
+        self.assertEquals("http://localhost/ldp-dummys/{}".format(dummy.pk), LDPResolver.resource_url(dummy))
+        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), LDPResolver.resource_path(dummy))
+        self.assertEquals("http://localhost/ldp-dummys/{}".format(dummy.pk), dummy.resource_url())
+        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), dummy.resource_path())
+        self.assertEquals("http://localhost/ldp-dummys", LDPResolver.container_url(dummy))
+        self.assertEquals("/ldp-dummys", LDPResolver.container_path(dummy))
+        self.assertEquals("http://localhost/dummys/", dummy.container_url())
+        self.assertEquals("/ldp-dummys", dummy.container_path())
diff --git a/djangoldp/tests/tests_save.py b/djangoldp/tests/tests_save.py
index 1117c928..7e05496a 100644
--- a/djangoldp/tests/tests_save.py
+++ b/djangoldp/tests/tests_save.py
@@ -4,7 +4,7 @@ from djangoldp.serializers import LDPSerializer
 from djangoldp.tests.models import Skill, JobOffer
 
 
-class Serializer(TestCase):
+class Save(TestCase):
 
     def test_save_m2m(self):
         skill1 = Skill.objects.create(title="skill1", obligatoire="obligatoire")
diff --git a/djangoldp/tests/tests_update.py b/djangoldp/tests/tests_update.py
index 7b232b44..622b55ef 100644
--- a/djangoldp/tests/tests_update.py
+++ b/djangoldp/tests/tests_update.py
@@ -5,7 +5,7 @@ from djangoldp.serializers import LDPSerializer
 from djangoldp.tests.models import Skill, JobOffer, Thread, Message
 
 
-class Serializer(TestCase):
+class Update(TestCase):
 
     def test_update(self):
         skill = Skill.objects.create(title="to drop", obligatoire="obligatoire")
diff --git a/djangoldp/tests/urls.py b/djangoldp/tests/urls.py
index 0066129b..8e1cbc86 100644
--- a/djangoldp/tests/urls.py
+++ b/djangoldp/tests/urls.py
@@ -1,6 +1,6 @@
 from django.conf import settings
 
-from djangoldp.tests.models import Skill, JobOffer, Message, Thread
+from djangoldp.tests.models import Skill, JobOffer, Message, Thread, Dummy
 from djangoldp.views import LDPViewSet
 from django.conf.urls import url
 
@@ -11,4 +11,5 @@ urlpatterns = [
     url(r'^messages/', LDPViewSet.urls(model=Message, permission_classes=[], fields=["@id", "text"], nested_fields=[])),
     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=[])),
 ]
\ No newline at end of file
-- 
GitLab


From 9ed012911dba50263c4b57fa50d433e8dffe02c3 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 19 Feb 2019 16:10:03 +0100
Subject: [PATCH 2/8] feature: add LDPModel class to manage instance path
 resolution

---
 djangoldp/models.py               | 35 +++++++++++++++++++++++++------
 djangoldp/resolver.py             | 17 ---------------
 djangoldp/tests/tests_resolver.py | 20 +++++++-----------
 3 files changed, 36 insertions(+), 36 deletions(-)
 delete mode 100644 djangoldp/resolver.py

diff --git a/djangoldp/models.py b/djangoldp/models.py
index bcb62f61..abd9ea79 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -5,19 +5,41 @@ from django.db import models
 class LDPModel(models.Model):
     ldp_path = None
 
-    def full_path(self):
-        return "{}/{}".format(self.container_path(), self.pk)
+    def get_resource_path(self):
+        return LDPModel.resource_path(self)
 
-    def container_path(self):
-        return self.ldp_path
+    def get_container_path(self):
+        return LDPModel.container_path(self)
+
+    @classmethod
+    def resource_path(cls, instance):
+        return "{}{}".format(LDPModel.container_path(instance), instance.pk)
+
+    @classmethod
+    def container_path(cls, instance):
+        if isinstance(instance, cls):
+            path = instance.ldp_path
+        else:
+            from django.urls import get_resolver
+            view_name = '{}-list'.format(instance._meta.object_name.lower())
+            path = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0], instance.pk)
+
+        if not path.startswith("/"):
+            path = "/{}".format(path)
+
+        if not path.endswith("/"):
+            path = "{}/".format(path)
+
+        return path
 
     class Meta:
         abstract = True
 
+
 class LDPSource(models.Model):
     container = models.URLField()
     federation = models.CharField(max_length=255)
-    
+
     class Meta:
         rdf_type = 'sib:source'
         ordering = ('federation',)
@@ -25,7 +47,7 @@ class LDPSource(models.Model):
             ('view_source', 'acl:Read'),
             ('control_source', 'acl:Control'),
         )
-    
+
     def __str__(self):
         return "{}: {}".format(self.federation, self.container)
 
@@ -37,6 +59,7 @@ class LDNotification(models.Model):
     type = models.CharField(max_length=255)
     summary = models.TextField()
     date = models.DateTimeField(auto_now_add=True)
+
     class Meta:
         permissions = (
             ('view_todo', 'Read'),
diff --git a/djangoldp/resolver.py b/djangoldp/resolver.py
deleted file mode 100644
index 949ae3f1..00000000
--- a/djangoldp/resolver.py
+++ /dev/null
@@ -1,17 +0,0 @@
-class LDPResolver:
-
-    @classmethod
-    def resource_url(cls, dummy):
-        pass
-
-    @classmethod
-    def container_url(cls, dummy):
-        pass
-
-    @classmethod
-    def resource_path(cls, dummy):
-        pass
-
-    @classmethod
-    def container_path(cls, dummy):
-        pass
diff --git a/djangoldp/tests/tests_resolver.py b/djangoldp/tests/tests_resolver.py
index 55818f6d..96b1be0f 100644
--- a/djangoldp/tests/tests_resolver.py
+++ b/djangoldp/tests/tests_resolver.py
@@ -1,6 +1,6 @@
 from django.test import TestCase
 
-from djangoldp.resolver import LDPResolver
+from djangoldp.models import LDPModel
 from djangoldp.tests.models import Dummy, LDPDummy
 
 
@@ -8,18 +8,12 @@ class UrlUtils(TestCase):
 
     def test_class_not_inheriting_ldp_model(self):
         dummy = Dummy.objects.create(some="text")
-        self.assertEquals("http://localhost/dummys/{}".format(dummy.pk), LDPResolver.resource_url(dummy))
-        self.assertEquals("/dummys/{}".format(dummy.pk), LDPResolver.resource_path(dummy))
-        self.assertEquals("http://localhost/dummys", LDPResolver.container_url(dummy))
-        self.assertEquals("/dummys", LDPResolver.container_path(dummy))
+        self.assertEquals("/dummys/", LDPModel.container_path(dummy))
+        self.assertEquals("/dummys/{}".format(dummy.pk), LDPModel.resource_path(dummy))
 
     def test_class_inheriting_ldp_model(self):
         dummy = LDPDummy.objects.create(some="text")
-        self.assertEquals("http://localhost/ldp-dummys/{}".format(dummy.pk), LDPResolver.resource_url(dummy))
-        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), LDPResolver.resource_path(dummy))
-        self.assertEquals("http://localhost/ldp-dummys/{}".format(dummy.pk), dummy.resource_url())
-        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), dummy.resource_path())
-        self.assertEquals("http://localhost/ldp-dummys", LDPResolver.container_url(dummy))
-        self.assertEquals("/ldp-dummys", LDPResolver.container_path(dummy))
-        self.assertEquals("http://localhost/dummys/", dummy.container_url())
-        self.assertEquals("/ldp-dummys", dummy.container_path())
+        self.assertEquals("/ldp-dummys/", dummy.get_container_path())
+        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), dummy.get_resource_path())
+        self.assertEquals("/ldp-dummys/", LDPModel.container_path(dummy))
+        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), LDPModel.resource_path(dummy))
-- 
GitLab


From 99b3ca9b64011090c11bc49c7f28602732e3b8f7 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 19 Feb 2019 16:18:33 +0100
Subject: [PATCH 3/8] syntax: add skipped test for the future "auto urls"
 feature

---
 djangoldp/tests/runner.py                          |  2 +-
 .../{tests_resolver.py => tests_ldp_model.py}      | 14 +++++++++++++-
 2 files changed, 14 insertions(+), 2 deletions(-)
 rename djangoldp/tests/{tests_resolver.py => tests_ldp_model.py} (64%)

diff --git a/djangoldp/tests/runner.py b/djangoldp/tests/runner.py
index 17419667..4e3bcd04 100644
--- a/djangoldp/tests/runner.py
+++ b/djangoldp/tests/runner.py
@@ -25,7 +25,7 @@ from django.test.runner import DiscoverRunner
 test_runner = DiscoverRunner(verbosity=1)
 
 failures = test_runner.run_tests([
-    'djangoldp.tests.tests_resolver',
+    'djangoldp.tests.tests_ldp_model',
     'djangoldp.tests.tests_save',
     'djangoldp.tests.tests_update'])
 if failures:
diff --git a/djangoldp/tests/tests_resolver.py b/djangoldp/tests/tests_ldp_model.py
similarity index 64%
rename from djangoldp/tests/tests_resolver.py
rename to djangoldp/tests/tests_ldp_model.py
index 96b1be0f..0bf48e49 100644
--- a/djangoldp/tests/tests_resolver.py
+++ b/djangoldp/tests/tests_ldp_model.py
@@ -1,10 +1,12 @@
+import unittest
+
 from django.test import TestCase
 
 from djangoldp.models import LDPModel
 from djangoldp.tests.models import Dummy, LDPDummy
 
 
-class UrlUtils(TestCase):
+class LDPModelTest(TestCase):
 
     def test_class_not_inheriting_ldp_model(self):
         dummy = Dummy.objects.create(some="text")
@@ -17,3 +19,13 @@ class UrlUtils(TestCase):
         self.assertEquals("/ldp-dummys/{}".format(dummy.pk), dummy.get_resource_path())
         self.assertEquals("/ldp-dummys/", LDPModel.container_path(dummy))
         self.assertEquals("/ldp-dummys/{}".format(dummy.pk), LDPModel.resource_path(dummy))
+
+
+    @unittest.skip("futur feature: avoid urls.py on apps")
+    def test_auto_url(self):
+        from django.urls import get_resolver
+        dummy = LDPDummy.objects.create(some="text")
+        view_name = '{}-list'.format(dummy._meta.object_name.lower())
+        path = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0], dummy.pk)
+
+        self.assertEquals(path, dummy.get_resource_path())
-- 
GitLab


From d7df4f31e188f27cf73265095c13f028e9d80146 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 19 Feb 2019 16:26:03 +0100
Subject: [PATCH 4/8] syntax: update readme for LDPModel and ldp_path

---
 README.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index e8525f1c..6dfacc1d 100644
--- a/README.md
+++ b/README.md
@@ -29,9 +29,10 @@ django-admin startproject myldpserver
 3. Create your django model inside a file myldpserver/myldpserver/models.py
 
 ```
-from django.db import models
+from djangoldp.models import LDPModel
 
-class Todo(models.Model):
+class Todo(LDPModel):
+    ldp_path = "/my-path/"
     name = models.CharField(max_length=255)
     deadline = models.DateTimeField()
 
-- 
GitLab


From df0a759f9559d4a33f4efc0a91c5709493577022 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 19 Feb 2019 16:58:57 +0100
Subject: [PATCH 5/8] syntax: Refactor after code review

---
 README.md                          |  8 +++++---
 djangoldp/models.py                | 20 ++++++++++----------
 djangoldp/tests/models.py          |  6 +++---
 djangoldp/tests/tests_ldp_model.py | 16 ++++++++--------
 4 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/README.md b/README.md
index 6dfacc1d..17b3fabe 100644
--- a/README.md
+++ b/README.md
@@ -27,12 +27,14 @@ django-admin startproject myldpserver
 ```
 
 3. Create your django model inside a file myldpserver/myldpserver/models.py
+Note that container_path will be use to resolve instance iri and container iri
+In the future it could also be used to auto configure django router (e.g. urls.py)
 
 ```
-from djangoldp.models import LDPModel
+from djangoldp.models import Model
 
-class Todo(LDPModel):
-    ldp_path = "/my-path/"
+class Todo(Model):
+    container_path = "/my-path/"
     name = models.CharField(max_length=255)
     deadline = models.DateTimeField()
 
diff --git a/djangoldp/models.py b/djangoldp/models.py
index abd9ea79..61d746a8 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -2,23 +2,23 @@ from django.conf import settings
 from django.db import models
 
 
-class LDPModel(models.Model):
-    ldp_path = None
+class Model(models.Model):
+    container_path = None
 
-    def get_resource_path(self):
-        return LDPModel.resource_path(self)
+    def get_absolute_url(self):
+        return Model.resource_id(self)
 
-    def get_container_path(self):
-        return LDPModel.container_path(self)
+    def get_container_id(self):
+        return Model.container_id(self)
 
     @classmethod
-    def resource_path(cls, instance):
-        return "{}{}".format(LDPModel.container_path(instance), instance.pk)
+    def resource_id(cls, instance):
+        return "{}{}".format(Model.container_id(instance), instance.pk)
 
     @classmethod
-    def container_path(cls, instance):
+    def container_id(cls, instance):
         if isinstance(instance, cls):
-            path = instance.ldp_path
+            path = instance.container_path
         else:
             from django.urls import get_resolver
             view_name = '{}-list'.format(instance._meta.object_name.lower())
diff --git a/djangoldp/tests/models.py b/djangoldp/tests/models.py
index 29b0a521..2622673f 100644
--- a/djangoldp/tests/models.py
+++ b/djangoldp/tests/models.py
@@ -1,7 +1,7 @@
 from django.conf import settings
 from django.db import models
 
-from djangoldp.models import LDPModel
+from djangoldp.models import Model
 
 
 class Skill(models.Model):
@@ -29,7 +29,7 @@ class Dummy(models.Model):
     some = models.CharField(max_length=255, blank=True, null=True)
 
 
-class LDPDummy(LDPModel):
+class LDPDummy(Model):
     some = models.CharField(max_length=255, blank=True, null=True)
-    ldp_path = "ldp-dummys"
+    container_path = "ldp-dummys"
 
diff --git a/djangoldp/tests/tests_ldp_model.py b/djangoldp/tests/tests_ldp_model.py
index 0bf48e49..8a17c88f 100644
--- a/djangoldp/tests/tests_ldp_model.py
+++ b/djangoldp/tests/tests_ldp_model.py
@@ -2,7 +2,7 @@ import unittest
 
 from django.test import TestCase
 
-from djangoldp.models import LDPModel
+from djangoldp.models import Model
 from djangoldp.tests.models import Dummy, LDPDummy
 
 
@@ -10,15 +10,15 @@ class LDPModelTest(TestCase):
 
     def test_class_not_inheriting_ldp_model(self):
         dummy = Dummy.objects.create(some="text")
-        self.assertEquals("/dummys/", LDPModel.container_path(dummy))
-        self.assertEquals("/dummys/{}".format(dummy.pk), LDPModel.resource_path(dummy))
+        self.assertEquals("/dummys/", Model.container_id(dummy))
+        self.assertEquals("/dummys/{}".format(dummy.pk), Model.resource_id(dummy))
 
     def test_class_inheriting_ldp_model(self):
         dummy = LDPDummy.objects.create(some="text")
-        self.assertEquals("/ldp-dummys/", dummy.get_container_path())
-        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), dummy.get_resource_path())
-        self.assertEquals("/ldp-dummys/", LDPModel.container_path(dummy))
-        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), LDPModel.resource_path(dummy))
+        self.assertEquals("/ldp-dummys/", dummy.get_container_id())
+        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), dummy.get_absolute_url())
+        self.assertEquals("/ldp-dummys/", Model.container_id(dummy))
+        self.assertEquals("/ldp-dummys/{}".format(dummy.pk), Model.resource_id(dummy))
 
 
     @unittest.skip("futur feature: avoid urls.py on apps")
@@ -28,4 +28,4 @@ class LDPModelTest(TestCase):
         view_name = '{}-list'.format(dummy._meta.object_name.lower())
         path = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0], dummy.pk)
 
-        self.assertEquals(path, dummy.get_resource_path())
+        self.assertEquals(path, dummy.get_absolute_url())
-- 
GitLab


From 9ee2a8502c3f3bc6fa5405797b9ab1db21a83c6d Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 19 Feb 2019 17:35:38 +0100
Subject: [PATCH 6/8] update: manage slug on custom model

---
 djangoldp/models.py      | 13 ++++++++++---
 djangoldp/serializers.py |  2 +-
 djangoldp/tests/urls.py  |  3 ++-
 3 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/djangoldp/models.py b/djangoldp/models.py
index 61d746a8..00c63943 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -1,10 +1,14 @@
 from django.conf import settings
 from django.db import models
+from django.urls import get_resolver
 
 
 class Model(models.Model):
     container_path = None
 
+    def get_container_path(self):
+        return self.container_path
+
     def get_absolute_url(self):
         return Model.resource_id(self)
 
@@ -13,16 +17,19 @@ class Model(models.Model):
 
     @classmethod
     def resource_id(cls, instance):
-        return "{}{}".format(Model.container_id(instance), instance.pk)
+        view_name = '{}-detail'.format(instance._meta.object_name.lower())
+        slug_field = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][1][0])
+        if slug_field.startswith('/'):
+            slug_field = slug_field[1:]
+        return "{}{}".format(Model.container_id(instance), getattr(instance, slug_field))
 
     @classmethod
     def container_id(cls, instance):
         if isinstance(instance, cls):
             path = instance.container_path
         else:
-            from django.urls import get_resolver
             view_name = '{}-list'.format(instance._meta.object_name.lower())
-            path = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0], instance.pk)
+            path = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0])
 
         if not path.startswith("/"):
             path = "/{}".format(path)
diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py
index 815be906..a2d0f6dc 100644
--- a/djangoldp/serializers.py
+++ b/djangoldp/serializers.py
@@ -41,7 +41,7 @@ class LDListMixin:
         try:
             object_list = dictionary["@graph"]
             view_name = '{}-list'.format(self.parent.Meta.model._meta.object_name.lower())
-            part_id = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0], self.parent.instance.pk)
+            part_id = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0])
             obj = next(filter(lambda o: part_id in o['@id'], object_list))
             list = super().get_value(obj)
             try:
diff --git a/djangoldp/tests/urls.py b/djangoldp/tests/urls.py
index 8e1cbc86..392b0e2b 100644
--- a/djangoldp/tests/urls.py
+++ b/djangoldp/tests/urls.py
@@ -1,6 +1,6 @@
 from django.conf import settings
 
-from djangoldp.tests.models import Skill, JobOffer, Message, Thread, Dummy
+from djangoldp.tests.models import Skill, JobOffer, Message, Thread, Dummy, LDPDummy
 from djangoldp.views import LDPViewSet
 from django.conf.urls import url
 
@@ -12,4 +12,5 @@ urlpatterns = [
     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=[])),
+    url(r'^ldp-dummys/', LDPViewSet.urls(model=LDPDummy, permission_classes=[])),
 ]
\ No newline at end of file
-- 
GitLab


From 3908a5e118d2fc26a34d623a6a1ab4b2066a0a1f Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Wed, 20 Feb 2019 11:53:37 +0100
Subject: [PATCH 7/8] update: add resolve functions on Model

---
 djangoldp/models.py                | 39 ++++++++++++++++++++++++------
 djangoldp/tests/tests_ldp_model.py |  8 ++++++
 2 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/djangoldp/models.py b/djangoldp/models.py
index 00c63943..f63ffd4b 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -21,7 +21,7 @@ class Model(models.Model):
         slug_field = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][1][0])
         if slug_field.startswith('/'):
             slug_field = slug_field[1:]
-        return "{}{}".format(Model.container_id(instance), getattr(instance, slug_field))
+        return "{}{}".format(cls.container_id(instance), getattr(instance, slug_field))
 
     @classmethod
     def container_id(cls, instance):
@@ -29,19 +29,44 @@ class Model(models.Model):
             path = instance.container_path
         else:
             view_name = '{}-list'.format(instance._meta.object_name.lower())
-            path = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0])
+            path = get_resolver().reverse(view_name)
 
-        if not path.startswith("/"):
-            path = "/{}".format(path)
-
-        if not path.endswith("/"):
-            path = "{}/".format(path)
+        path = cls.__clean_path(path)
 
         return path
 
     class Meta:
         abstract = True
 
+    @classmethod
+    def resolve_id(cls, id):
+        id = cls.__clean_path(id)
+        view, args, kwargs = get_resolver().resolve(id)
+        return view.initkwargs['model'].objects.get(**kwargs)
+
+    @classmethod
+    def resolve_container(cls, path):
+        path = cls.__clean_path(path)
+        view, args, kwargs = get_resolver().resolve(path)
+        return view.initkwargs['model']
+
+    @classmethod
+    def resolve(cls, path):
+        container = cls.resolve_container(path)
+        try:
+            resolve_id = cls.resolve_id(path)
+        except:
+            resolve_id = None
+        return container, resolve_id
+
+    @classmethod
+    def __clean_path(cls, path):
+        if not path.startswith("/"):
+            path = "/{}".format(path)
+        if not path.endswith("/"):
+            path = "{}/".format(path)
+        return path
+
 
 class LDPSource(models.Model):
     container = models.URLField()
diff --git a/djangoldp/tests/tests_ldp_model.py b/djangoldp/tests/tests_ldp_model.py
index 8a17c88f..56bbe552 100644
--- a/djangoldp/tests/tests_ldp_model.py
+++ b/djangoldp/tests/tests_ldp_model.py
@@ -20,6 +20,14 @@ class LDPModelTest(TestCase):
         self.assertEquals("/ldp-dummys/", Model.container_id(dummy))
         self.assertEquals("/ldp-dummys/{}".format(dummy.pk), Model.resource_id(dummy))
 
+    def test_from_resolve_id(self):
+        saved_instance = Dummy.objects.create(some="text")
+        result = Model.resolve_id("/dummys/{}".format(saved_instance.pk))
+        self.assertEquals(saved_instance, result)
+
+    def test_resolve_container(self):
+        result = Model.resolve_container("/dummys/")
+        self.assertEquals(Dummy, result)
 
     @unittest.skip("futur feature: avoid urls.py on apps")
     def test_auto_url(self):
-- 
GitLab


From 5404fcce35a450771a0fb72014055702ace5000b Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Wed, 20 Feb 2019 12:29:23 +0100
Subject: [PATCH 8/8] syntax: refactor to use Model utilities functions

---
 djangoldp/serializers.py | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py
index a2d0f6dc..18a63a1d 100644
--- a/djangoldp/serializers.py
+++ b/djangoldp/serializers.py
@@ -16,6 +16,8 @@ from rest_framework.settings import api_settings
 from rest_framework.utils.field_mapping import get_nested_relation_kwargs
 from rest_framework.utils.serializer_helpers import ReturnDict
 
+from djangoldp.models import Model
+
 
 class LDListMixin:
     def to_internal_value(self, data):
@@ -40,9 +42,8 @@ class LDListMixin:
     def get_value(self, dictionary):
         try:
             object_list = dictionary["@graph"]
-            view_name = '{}-list'.format(self.parent.Meta.model._meta.object_name.lower())
-            part_id = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0])
-            obj = next(filter(lambda o: part_id in o['@id'], object_list))
+            container_id = Model.container_id(self.parent.instance)
+            obj = next(filter(lambda o: container_id in o['@id'], object_list))
             list = super().get_value(obj)
             try:
                 list = next(filter(lambda o: list['@id'] == o['@id'], object_list))
@@ -197,9 +198,8 @@ class LDPSerializer(HyperlinkedModelSerializer):
             def get_value(self, dictionary):
                 try:
                     object_list = dictionary["@graph"]
-                    part_id = '/{}'.format(get_resolver().reverse_dict[self.parent_view_name][0][0][0],
-                                           self.parent.instance.pk)
-                    obj = next(filter(lambda o: part_id in o['@id'], object_list))
+                    resource_id = Model.resource_id(self.parent.instance)
+                    obj = next(filter(lambda o: resource_id in o['@id'], object_list))
                     return super().get_value(obj)
                 except KeyError:
                     return super().get_value(dictionary)
@@ -288,10 +288,8 @@ class LDPSerializer(HyperlinkedModelSerializer):
     def get_value(self, dictionary):
         try:
             object_list = dictionary["@graph"]
-            view_name = '{}-list'.format(self.parent.Meta.model._meta.object_name.lower())
-            part_id = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0],
-                                   self.parent.instance.pk)
-            obj = next(filter(lambda o: part_id in o[self.url_field_name], object_list))
+            container_id = Model.container_path(self.parent.instance)
+            obj = next(filter(lambda o: container_id in o[self.url_field_name], object_list))
             item = super().get_value(obj)
             full_item = None
             if item is empty:
-- 
GitLab