diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py
index 0b08172886563f4f66583fbc6cc9bf6e635cbaf7..19e7c2c0213f348758ce168867beda32ef695002 100644
--- a/djangoldp/serializers.py
+++ b/djangoldp/serializers.py
@@ -18,6 +18,7 @@ class JsonLdRelatedField(HyperlinkedRelatedField):
         #get the field name associated with the url of the view
         try:
             lookup_field = get_resolver().reverse_dict[self.view_name][0][0][1][0]
+            print(self.view_name, self.queryset, lookup_field)
             self.lookup_field = lookup_field
             self.lookup_url_kwarg = lookup_field
         except MultiValueDictKeyError:
diff --git a/djangoldp/views.py b/djangoldp/views.py
index 4c1e00dcebf6c8113e60753013600be57fd2a115..d1cb4b8f72115b2c12e1008c3c064dc0f2ed2639 100644
--- a/djangoldp/views.py
+++ b/djangoldp/views.py
@@ -28,6 +28,13 @@ class NoCSRFAuthentication(SessionAuthentication):
         return
 
 class LDPViewSetGenerator(ModelViewSet):
+    """An extension of ModelViewSet that generates automatically URLs for the model"""
+    model = None
+    nested_fields = []
+    model_prefix = None
+    list_actions = {'get': 'list', 'post': 'create'}
+    detail_actions = {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}
+    
     @classonlymethod
     def get_model(cls, **kwargs):
         '''gets the model in the arguments or in the viewset definition'''
@@ -37,65 +44,47 @@ class LDPViewSetGenerator(ModelViewSet):
         return model
     
     @classonlymethod
-    def get_detail_url(cls, lookup_field=None, base_url='', **kwargs):
-        '''builds the detail url based on the lookup_field'''
-        lookup_field = lookup_field or kwargs.get('lookup_field') or cls.lookup_field
-        if lookup_field and lookup_field != 'pk':
-            return r'{}(?P<{}>[\w-]+)/'.format(base_url, lookup_field)
-        return  r'{}(?P<pk>\d+)/'.format(base_url)
+    def get_lookup_arg(cls, **kwargs):
+        return kwargs.get('lookup_url_kwarg') or cls.lookup_url_kwarg or kwargs.get('lookup_field') or cls.lookup_field
     
     @classonlymethod
-    def get_nested_urls(cls, detail_url, model_name, **kwargs):
-        nested_field = kwargs.get('nested_field') or cls.nested_field
-        if not nested_field:
-            return []
-        
-        base_url = r'{}{}/'.format(detail_url, nested_field)
-        related_field = kwargs['model']._meta.get_field(nested_field)
-        related_name = related_field.related_query_name()
-        related_model = related_field.related_model
-        nested_lookup_field = related_model._meta.object_name.lower()+'_id'
-        
-        nested_args = {
-             'model': related_model,
-             'exclude': (), #exclude related_name for foreignkey attributes 
-             'parent_model': kwargs['model'],
-             'nested_field': nested_field,
-             'nested_related_name': related_name
-        }
-        nested_detail_url = cls.get_detail_url(nested_lookup_field, base_url)
-        return [
-            url(base_url+'$', cls.as_view(cls.list_actions, **nested_args), name='{}-{}-list'.format(model_name, nested_field)),
-            url(nested_detail_url+'$', cls.as_view(cls.detail_actions, **nested_args), name='{}-{}-detail'.format(model_name, nested_field)),
-        ]
+    def get_detail_expr(cls, lookup_field=None, **kwargs):
+        '''builds the detail url based on the lookup_field'''
+        lookup_field = lookup_field or cls.get_lookup_arg(**kwargs)
+        lookup_group = r'\d' if lookup_field == 'pk' else r'[\w-]'
+        return r'(?P<{}>{}+)/'.format(lookup_field, lookup_group)
     
     @classonlymethod
     def urls(cls, **kwargs):
         kwargs['model'] = cls.get_model(**kwargs)
         model_name = kwargs['model']._meta.object_name.lower()
-        detail_url = cls.get_detail_url(**kwargs)
+        if kwargs.get('model_prefix'):
+            model_name = '{}-{}'.format(kwargs['model_prefix'], model_name)
+        detail_expr = cls.get_detail_expr(**kwargs)
         
-        return include(
-            cls.get_nested_urls(detail_url, model_name, **kwargs) + [
-                url(r'^$', cls.as_view(cls.list_actions, **kwargs), name='{}-list'.format(model_name)),
-                url(detail_url+'$', cls.as_view(cls.detail_actions, **kwargs), name='{}-detail'.format(model_name)),
-            ])
+        urls = [
+                url('^$', cls.as_view(cls.list_actions, **kwargs), name='{}-list'.format(model_name)),
+                url('^'+detail_expr+'$', cls.as_view(cls.detail_actions, **kwargs), name='{}-detail'.format(model_name)),
+            ]
+        
+        for field in kwargs.get('nested_fields') or cls.nested_fields:
+            urls.append(url(detail_expr+field+'/', LDPNestedViewSet.nested_urls(field, **kwargs)))
+        
+        return include(urls)
 
 class LDPViewSet(LDPViewSetGenerator):
-    model = None
+    """An automatically generated viewset that serves models following the Linked Data Platform convention"""
     fields = None
     exclude = None
-    parent_model = None
-    nested_field = None
-    nested_related_name = None
-    list_actions = {'get': 'list', 'post': 'create'}
-    detail_actions = {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}
     renderer_classes = (JSONLDRenderer, )
     parser_classes = (JSONLDParser, )
     authentication_classes = (NoCSRFAuthentication,)
     
     def __init__(self, **kwargs):
         super().__init__(**kwargs)
+        self.serializer_class = self.build_serializer()
+    
+    def build_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}}}
@@ -104,22 +93,14 @@ class LDPViewSet(LDPViewSetGenerator):
         else:
             meta_args['exclude'] = self.exclude or ()
         meta_class = type('Meta', (), meta_args)
-        self.serializer_class = type(LDPSerializer)(model_name+'Serializer', (LDPSerializer,), {'Meta': meta_class})
-    
-    def get_parent(self):
-        return get_object_or_404(self.parent_model, id=self.kwargs[self.lookup_field])
+        return type(LDPSerializer)(model_name+'Serializer', (LDPSerializer,), {'Meta': meta_class})
     
-    def perform_create(self, serializer):
-        create_args = {}
-        if self.parent_model:
-            create_args[self.nested_related_name] = self.get_parent()
+    def perform_create(self, serializer, **kwargs):
         if hasattr(self.model._meta, 'auto_author'):
-            create_args[self.model._meta.auto_author] = self.request.user
-        serializer.save(**create_args)
+            kwargs[self.model._meta.auto_author] = self.request.user
+        serializer.save(**kwargs)
     
     def get_queryset(self, *args, **kwargs):
-        if self.parent_model:
-            return getattr(self.get_parent(), self.nested_field).all()
         if self.model:
             return self.model.objects.all()
         else:
@@ -133,3 +114,34 @@ class LDPViewSet(LDPViewSetGenerator):
         response["Access-Control-Allow-Credentials"] = 'true'
         response["Accept-Post"] = "application/ld+json"
         return response
+
+class LDPNestedViewSet(LDPViewSet):
+    """A special case of LDPViewSet serving objects of a relation of a given object (e.g. members of a group, or skills of a user)"""
+    parent_model = None
+    parent_lookup_field = None
+    nested_field = None
+    nested_related_name = None
+    
+    def get_parent(self):
+        return get_object_or_404(self.parent_model, **{self.parent_lookup_field: self.kwargs[self.parent_lookup_field]})
+    
+    def perform_create(self, serializer, **kwargs):
+        kwargs[self.nested_related_name] = self.get_parent()
+        super().perform_create(serializer, **kwargs)
+    
+    def get_queryset(self, *args, **kwargs):
+        return getattr(self.get_parent(), self.nested_field).all()
+    
+    @classonlymethod
+    def nested_urls(cls, nested_field, **kwargs):
+        related_field = cls.get_model(**kwargs)._meta.get_field(nested_field)
+        
+        return cls.urls(
+            model = related_field.related_model,
+            exclude = (),
+            parent_model = cls.get_model(**kwargs),
+            nested_field = nested_field,
+            nested_related_name = related_field.related_query_name(),
+            parent_lookup_field = cls.get_lookup_arg(**kwargs),
+            model_prefix = cls.get_model(**kwargs)._meta.object_name.lower(),
+            lookup_url_kwarg = related_field.related_model._meta.object_name.lower()+'_id')