Implements get_absolute_url for nodes (Feature #17). Fixes that mysterious 'name...
[philo.git] / models / nodes.py
index bb1601e..23be42b 100644 (file)
@@ -4,9 +4,13 @@ from django.contrib.contenttypes import generic
 from django.contrib.sites.models import Site
 from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
 from django.contrib.sites.models import Site
 from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
-from philo.models.base import TreeEntity, Entity
+from django.core.urlresolvers import resolve, clear_url_caches
+from django.template import add_to_builtins as register_templatetags
+from inspect import getargspec
+from philo.models.base import TreeEntity, Entity, QuerySetMapper, register_value_model
 from philo.utils import ContentTypeSubclassLimiter
 from philo.validators import RedirectValidator
 from philo.utils import ContentTypeSubclassLimiter
 from philo.validators import RedirectValidator
+from philo.exceptions import ViewDoesNotProvideSubpaths, AncestorDoesNotExist
 
 
 _view_content_type_limiter = ContentTypeSubclassLimiter(None)
 
 
 _view_content_type_limiter = ContentTypeSubclassLimiter(None)
@@ -19,10 +23,19 @@ class Node(TreeEntity):
        
        @property
        def accepts_subpath(self):
        
        @property
        def accepts_subpath(self):
-               return self.view.accepts_subpath
+               if self.view:
+                       return self.view.accepts_subpath
+               return False
        
        
-       def render_to_response(self, request, path=None, subpath=None):
-               return self.view.render_to_response(self, request, path, subpath)
+       def render_to_response(self, request, path=None, subpath=None, extra_context=None):
+               return self.view.render_to_response(self, request, path, subpath, extra_context)
+       
+       def get_absolute_url(self):
+               root = Site.objects.get_current().root_node
+               try:
+                       return '/%s' % self.get_path(root=root)
+               except AncestorDoesNotExist:
+                       return None
        
        class Meta:
                app_label = 'philo'
        
        class Meta:
                app_label = 'philo'
@@ -37,12 +50,20 @@ class View(Entity):
        
        accepts_subpath = False
        
        
        accepts_subpath = False
        
-       def render_to_response(self, node, request, path=None, subpath=None):
+       def get_subpath(self, obj):
+               raise ViewDoesNotProvideSubpaths
+       
+       def attributes_with_node(self, node):
+               return QuerySetMapper(self.attribute_set, passthrough=node.attributes)
+       
+       def relationships_with_node(self, node):
+               return QuerySetMapper(self.relationship_set, passthrough=node.relationships)
+       
+       def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
                raise NotImplementedError('View subclasses must implement render_to_response.')
        
        class Meta:
                abstract = True
                raise NotImplementedError('View subclasses must implement render_to_response.')
        
        class Meta:
                abstract = True
-               app_label = 'philo'
 
 
 _view_content_type_limiter.cls = View
 
 
 _view_content_type_limiter.cls = View
@@ -53,17 +74,23 @@ class MultiView(View):
        
        urlpatterns = []
        
        
        urlpatterns = []
        
-       def render_to_response(self, node, request, path=None, subpath=None):
+       def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
+               clear_url_caches()
                if not subpath:
                        subpath = ""
                subpath = "/" + subpath
                if not subpath:
                        subpath = ""
                subpath = "/" + subpath
-               from django.core.urlresolvers import resolve
                view, args, kwargs = resolve(subpath, urlconf=self)
                view, args, kwargs = resolve(subpath, urlconf=self)
+               view_args = getargspec(view)
+               if extra_context is not None and ('extra_context' in view_args[0] or view_args[2] is not None):
+                       if 'extra_context' in kwargs:
+                               extra_context.update(kwargs['extra_context'])
+                       kwargs['extra_context'] = extra_context
+               if 'node' in view_args[0] or view_args[2] is not None:
+                       kwargs['node'] = node
                return view(request, *args, **kwargs)
        
        class Meta:
                abstract = True
                return view(request, *args, **kwargs)
        
        class Meta:
                abstract = True
-               app_label = 'philo'
 
 
 class Redirect(View):
 
 
 class Redirect(View):
@@ -74,7 +101,7 @@ class Redirect(View):
        target = models.CharField(max_length=200, validators=[RedirectValidator()])
        status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')
        
        target = models.CharField(max_length=200, validators=[RedirectValidator()])
        status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')
        
-       def render_to_response(self, node, request, path=None, subpath=None):
+       def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
                response = HttpResponseRedirect(self.target)
                response.status_code = self.status_code
                return response
                response = HttpResponseRedirect(self.target)
                response.status_code = self.status_code
                return response
@@ -89,11 +116,18 @@ class File(View):
        mimetype = models.CharField(max_length=255)
        file = models.FileField(upload_to='philo/files/%Y/%m/%d')
        
        mimetype = models.CharField(max_length=255)
        file = models.FileField(upload_to='philo/files/%Y/%m/%d')
        
-       def render_to_response(self, node, request, path=None, subpath=None):
+       def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
                wrapper = FileWrapper(self.file)
                response = HttpResponse(wrapper, content_type=self.mimetype)
                response['Content-Length'] = self.file.size
                return response
        
        class Meta:
                wrapper = FileWrapper(self.file)
                response = HttpResponse(wrapper, content_type=self.mimetype)
                response['Content-Length'] = self.file.size
                return response
        
        class Meta:
-               app_label = 'philo'
\ No newline at end of file
+               app_label = 'philo'
+       
+       def __unicode__(self):
+               return self.file.name
+
+
+register_templatetags('philo.templatetags.nodes')
+register_value_model(Node)
\ No newline at end of file