From 7cc2242d22cea083e75d555afa4105fd797554c1 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste <bleme@pm.me> Date: Tue, 26 Feb 2019 16:32:17 +0000 Subject: [PATCH] update: Automatically generate urls from models --- README.md | 22 ++++++++++++++----- djangoldp/models.py | 23 +++++++++++++++----- djangoldp/tests/runner.py | 1 + djangoldp/tests/tests_ldp_model.py | 3 +-- djangoldp/tests/urls.py | 10 ++++----- djangoldp/urls.py | 35 ++++++++++++++++++++++++++++++ djangoldp/views.py | 2 +- 7 files changed, 77 insertions(+), 19 deletions(-) create mode 100644 djangoldp/urls.py diff --git a/README.md b/README.md index 07ac1cf2..316e9a27 100644 --- a/README.md +++ b/README.md @@ -34,13 +34,19 @@ In the future it could also be used to auto configure django router (e.g. urls.p from djangoldp.models import Model class Todo(Model): - container_path = "/my-path/" name = models.CharField(max_length=255) deadline = models.DateTimeField() ``` -3.1. Configure field visibility (optional) +3.1. Configure container path (optional) +By default it will be "todos/" with an S for model called Todo + +``` +<Model>._meta.container_path = "/my-path/" +``` + +3.2. Configure field visibility (optional) Note that at this stage you can limit access to certain fields of models using ``` @@ -68,12 +74,18 @@ from djangoldp.views import LDPViewSet from .models import Todo urlpatterns = [ - url(r'^todos/', LDPViewSet.urls(model=Todo)), - url(r'^admin/', admin.site.urls), + url(r'^', include('djangoldp.urls')), + url(r'^admin/', admin.site.urls), # Optional ] ``` -This creates 2 routes, one for the list, and one with an ID listing the detail of an object. +This creates 2 routes for each Model, one for the list, and one with an ID listing the detail of an object. + +You could also only use this line in settings.py instead: + +``` +ROOT_URLCONF = 'djangoldp.urls' +``` 5. In the settings.py file, add your application name at the beginning of the application list, and add the following lines diff --git a/djangoldp/models.py b/djangoldp/models.py index 151cb7d8..242dea66 100644 --- a/djangoldp/models.py +++ b/djangoldp/models.py @@ -4,10 +4,22 @@ from django.urls import get_resolver class Model(models.Model): - container_path = None - def get_container_path(self): - return self.container_path + @classmethod + def get_view_set(cls): + view_set = getattr(cls._meta, 'view_set', None) + if view_set is None: + from djangoldp.views import LDPViewSet + view_set = LDPViewSet + return view_set + + @classmethod + def get_container_path(cls): + path = getattr(cls._meta, 'container_path', None) + if path is None: + path = "{}s".format(cls._meta.object_name.lower()) + + return path def get_absolute_url(self): return Model.resource_id(self) @@ -26,9 +38,7 @@ class Model(models.Model): @classmethod def container_id(cls, instance): if isinstance(instance, cls): - path = instance.container_path - if path is None: - path = "{}s".format(instance._meta.object_name.lower()) + path = instance.get_container_path() else: view_name = '{}-list'.format(instance._meta.object_name.lower()) path = get_resolver().reverse(view_name) @@ -69,6 +79,7 @@ class Model(models.Model): path = "{}/".format(path) return path + class LDPSource(models.Model): container = models.URLField() federation = models.CharField(max_length=255) diff --git a/djangoldp/tests/runner.py b/djangoldp/tests/runner.py index 70074c5b..47a4548b 100644 --- a/djangoldp/tests/runner.py +++ b/djangoldp/tests/runner.py @@ -9,6 +9,7 @@ settings.configure(DEBUG=True, } }, ROOT_URLCONF='djangoldp.tests.urls', + DJANGOLDP_PACKAGES=['djangoldp.tests'], INSTALLED_APPS=('django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', diff --git a/djangoldp/tests/tests_ldp_model.py b/djangoldp/tests/tests_ldp_model.py index 6400378c..329899c0 100644 --- a/djangoldp/tests/tests_ldp_model.py +++ b/djangoldp/tests/tests_ldp_model.py @@ -29,11 +29,10 @@ class LDPModelTest(TestCase): result = Model.resolve_container("/dummys/") self.assertEquals(Dummy, result) - @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) + path = '/{}{}'.format(get_resolver().reverse_dict[view_name][0][0][0], dummy.pk) self.assertEquals(path, dummy.get_absolute_url()) diff --git a/djangoldp/tests/urls.py b/djangoldp/tests/urls.py index 392b0e2b..5062860e 100644 --- a/djangoldp/tests/urls.py +++ b/djangoldp/tests/urls.py @@ -1,9 +1,8 @@ from django.conf import settings +from django.conf.urls import url, include -from djangoldp.tests.models import Skill, JobOffer, Message, Thread, Dummy, LDPDummy +from djangoldp.tests.models import Skill, JobOffer, Message, Thread, Dummy from djangoldp.views import LDPViewSet -from django.conf.urls import url - urlpatterns = [ url(r'^skills/', LDPViewSet.urls(model=Skill, permission_classes=[], fields=["@id", "title"], nested_fields=[])), @@ -12,5 +11,6 @@ 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 + url(r'^', include('djangoldp.urls')), +] + diff --git a/djangoldp/urls.py b/djangoldp/urls.py new file mode 100644 index 00000000..3fc889b9 --- /dev/null +++ b/djangoldp/urls.py @@ -0,0 +1,35 @@ +from importlib import import_module + +from django.conf import settings +from django.conf.urls import url, include + +from djangoldp.models import LDPSource, Model +from djangoldp.views import LDPSourceViewSet + + +def __clean_path(path): + if path.startswith("/"): + path = path[1:] + if not path.endswith("/"): + path = "{}/".format(path) + return path + + +urlpatterns = [ + url(r'^sources/', LDPSourceViewSet.urls(model=LDPSource)), +] + +for package in settings.DJANGOLDP_PACKAGES: + import_module('{}.models'.format(package)) + +model_classes = {cls.__name__: cls for cls in Model.__subclasses__()} + +for class_name in model_classes: + model_class = model_classes[class_name] + path = __clean_path(model_class.get_container_path()) + urls_fct = model_class.get_view_set().urls + urlpatterns.append(url(r'^' + path, include( + urls_fct(model=model_class, + permission_classes=getattr(model_class._meta, 'permission_classes', []), + fields=getattr(model_class._meta, 'serializer_fields', []), + nested_fields=getattr(model_class._meta, 'nested_fields', []))))) diff --git a/djangoldp/views.py b/djangoldp/views.py index 3ccfdf73..a6e8c91b 100644 --- a/djangoldp/views.py +++ b/djangoldp/views.py @@ -6,6 +6,7 @@ from django.core.urlresolvers import get_resolver from django.db.utils import OperationalError from django.shortcuts import get_object_or_404 from django.utils.decorators import classonlymethod +from djangoldp.models import LDPSource from guardian.shortcuts import get_objects_for_user from pyld import jsonld from rest_framework.authentication import SessionAuthentication @@ -13,7 +14,6 @@ from rest_framework.parsers import JSONParser from rest_framework.renderers import JSONRenderer from rest_framework.viewsets import ModelViewSet -from .models import LDPSource from .serializers import LDPSerializer -- GitLab