Initial implementation of node_url templatetag.
authorJoseph Spiros <joseph.spiros@ithinksw.com>
Thu, 15 Jul 2010 01:37:13 +0000 (21:37 -0400)
committerJoseph Spiros <joseph.spiros@ithinksw.com>
Thu, 15 Jul 2010 02:30:22 +0000 (22:30 -0400)
contrib/penfield/models.py
exceptions.py [new file with mode: 0644]
models/base.py
models/nodes.py
models/pages.py
templatetags/nodes.py [new file with mode: 0644]

index 0d8a374..7da8e08 100644 (file)
@@ -1,7 +1,9 @@
 from django.db import models
 from django.conf import settings
 from philo.models import Tag, Titled, Entity, MultiView, Page, register_value_model
 from django.db import models
 from django.conf import settings
 from philo.models import Tag, Titled, Entity, MultiView, Page, register_value_model
+from philo.exceptions import ViewCanNotProvideSubpath
 from django.conf.urls.defaults import url, patterns
 from django.conf.urls.defaults import url, patterns
+from django.core.urlresolvers import reverse
 from django.http import Http404, HttpResponse
 from datetime import datetime
 from philo.contrib.penfield.utils import paginate
 from django.http import Http404, HttpResponse
 from datetime import datetime
 from philo.contrib.penfield.utils import paginate
@@ -59,6 +61,22 @@ class BlogView(MultiView):
        def __unicode__(self):
                return u'BlogView for %s' % self.blog.title
        
        def __unicode__(self):
                return u'BlogView for %s' % self.blog.title
        
+       def get_subpath(self, obj):
+               if isinstance(obj, BlogEntry):
+                       if obj.blog == self.blog:
+                               entry_view_args = {'slug': obj.slug}
+                               if self.entry_permalink_style in 'DMY':
+                                       entry_view_args.update({'year': str(obj.date.year).zfill(4)})
+                                       if self.entry_permalink_style in 'DM':
+                                               entry_view_args.update({'month': str(obj.date.month).zfill(2)})
+                                               if self.entry_permalink_style == 'D':
+                                                       entry_view_args.update({'day': str(obj.date.day).zfill(2)})
+                               return reverse(self.entry_view, urlconf=self, kwargs=entry_view_args)
+               elif isinstance(obj, Tag):
+                       if obj in self.blog.entry_tags:
+                               return reverse(self.tag_view, urlconf=self, kwargs={'tag_slugs': obj.slug})
+               raise ViewCanNotProvideSubpath
+       
        @property
        def urlpatterns(self):
                base_patterns = patterns('',
        @property
        def urlpatterns(self):
                base_patterns = patterns('',
diff --git a/exceptions.py b/exceptions.py
new file mode 100644 (file)
index 0000000..b40f08a
--- /dev/null
@@ -0,0 +1,7 @@
+class ViewDoesNotProvideSubpaths(Exception):
+       """ Raised by get_subpath when the View does not provide subpaths (the default). """
+       silent_variable_failure = True
+
+class ViewCanNotProvideSubpath(Exception):
+       """ Raised by get_subpath when the View can not provide a subpath for the supplied object. """
+       silent_variable_failure = True
\ No newline at end of file
index 2f5bf93..6f23191 100644 (file)
@@ -159,13 +159,29 @@ class TreeModel(models.Model):
        parent = models.ForeignKey('self', related_name='children', null=True, blank=True)
        slug = models.SlugField()
        
        parent = models.ForeignKey('self', related_name='children', null=True, blank=True)
        slug = models.SlugField()
        
-       def get_path(self, pathsep='/', field='slug'):
-               path = getattr(self, field, '?')
-               parent = self.parent
+       def has_ancestor(self, ancestor):
+               parent = self
                while parent:
                while parent:
-                       path = getattr(parent, field, '?') + pathsep + path
+                       if parent == ancestor:
+                               return True
                        parent = parent.parent
                        parent = parent.parent
-               return path
+               return False
+       
+       def get_path(self, root=None, pathsep='/', field='slug'):
+               if root is not None and self.has_ancestor(root):
+                       path = ''
+                       parent = self
+                       while parent and parent != root:
+                               path = getattr(parent, field, '?') + pathsep + path
+                               parent = parent.parent
+                       return path
+               else:
+                       path = getattr(self, field, '?')
+                       parent = self.parent
+                       while parent and parent != root:
+                               path = getattr(parent, field, '?') + pathsep + path
+                               parent = parent.parent
+                       return path
        path = property(get_path)
        
        def __unicode__(self):
        path = property(get_path)
        
        def __unicode__(self):
index 1e7622a..f46ddce 100644 (file)
@@ -5,10 +5,12 @@ from django.contrib.sites.models import Site
 from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
 from django.core.urlresolvers import resolve
 from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
 from django.core.urlresolvers import resolve
+from django.template import add_to_builtins as register_templatetags
 from inspect import getargspec
 from philo.models.base import TreeEntity, Entity, QuerySetMapper
 from philo.utils import ContentTypeSubclassLimiter
 from philo.validators import RedirectValidator
 from inspect import getargspec
 from philo.models.base import TreeEntity, Entity, QuerySetMapper
 from philo.utils import ContentTypeSubclassLimiter
 from philo.validators import RedirectValidator
+from philo.exceptions import ViewDoesNotProvideSubpaths
 
 
 _view_content_type_limiter = ContentTypeSubclassLimiter(None)
 
 
 _view_content_type_limiter = ContentTypeSubclassLimiter(None)
@@ -21,7 +23,9 @@ 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, extra_context=None):
                return self.view.render_to_response(self, request, path, subpath, extra_context)
        
        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)
@@ -39,6 +43,9 @@ class View(Entity):
        
        accepts_subpath = False
        
        
        accepts_subpath = False
        
+       def get_subpath(self, obj):
+               raise ViewDoesNotProvideSubpaths
+       
        def attributes_with_node(self, node):
                return QuerySetMapper(self.attribute_set, passthrough=node.attributes)
        
        def attributes_with_node(self, node):
                return QuerySetMapper(self.attribute_set, passthrough=node.attributes)
        
@@ -111,4 +118,7 @@ class File(View):
                app_label = 'philo'
        
        def __unicode__(self):
                app_label = 'philo'
        
        def __unicode__(self):
-               return self.file.name
\ No newline at end of file
+               return self.file.name
+
+
+register_templatetags('philo.templatetags.nodes')
\ No newline at end of file
index 5f75494..ff8e876 100644 (file)
@@ -101,7 +101,7 @@ class Page(View):
        def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
                context = {}
                context.update(extra_context or {})
        def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
                context = {}
                context.update(extra_context or {})
-               context.update({'page': self, 'attributes': self.attributes_with_node(node), 'relationships': self.relationships_with_node(node)})
+               context.update({'node': node, 'page': self, 'attributes': self.attributes_with_node(node), 'relationships': self.relationships_with_node(node)})
                return HttpResponse(self.template.django_template.render(RequestContext(request, context)), mimetype=self.template.mimetype)
        
        def __unicode__(self):
                return HttpResponse(self.template.django_template.render(RequestContext(request, context)), mimetype=self.template.mimetype)
        
        def __unicode__(self):
diff --git a/templatetags/nodes.py b/templatetags/nodes.py
new file mode 100644 (file)
index 0000000..3be8194
--- /dev/null
@@ -0,0 +1,76 @@
+from django import template
+from django.conf import settings
+from django.contrib.sites.models import Site
+
+
+register = template.Library()
+
+
+class NodeURLNode(template.Node):
+       def __init__(self, node, with_obj, as_var):
+               if node is not None:
+                       self.node = template.Variable(node)
+               else:
+                       self.node = None
+               
+               if with_obj is not None:
+                       self.with_obj = template.Variable(with_obj)
+               else:
+                       self.with_obj = None
+               
+               self.as_var = as_var
+       
+       def render(self, context):
+               try:
+                       if self.node:
+                               node = self.node.resolve(context)
+                       else:
+                               node = context['node']
+                       current_site = Site.objects.get_current()
+                       if node.has_ancestor(current_site.root_node):
+                               url = node.get_path(root=current_site.root_node)
+                               if self.with_obj:
+                                       with_obj = self.with_obj.resolve(context)
+                                       url += node.view.get_subpath(with_obj)
+                       else:
+                               return settings.TEMPLATE_STRING_IF_INVALID
+                       
+                       if self.as_var:
+                               context[self.as_var] = url
+                               return settings.TEMPLATE_STRING_IF_INVALID
+                       else:
+                               return url
+               except:
+                       return settings.TEMPLATE_STRING_IF_INVALID
+
+
+@register.tag(name='node_url')
+def do_node_url(parser, token):
+       """
+       {% node_url [<node>] [with <obj>] [as <var>] %}
+       """
+       params = token.split_contents()
+       tag = params[0]
+       
+       if len(params) <= 6:
+               node = None
+               with_obj = None
+               as_var = None
+               remaining_tokens = params[1:]
+               while remaining_tokens:
+                       option_token = remaining_tokens.pop(0)
+                       if option_token == 'with':
+                               try:
+                                       with_obj = remaining_tokens.pop(0)
+                               except IndexError:
+                                       raise template.TemplateSyntaxError('"%s" template tag option "with" requires an argument specifying an object handled by the view on the node' % tag)
+                       elif option_token == 'as':
+                               try:
+                                       as_var = remaining_tokens.pop(0)
+                               except IndexError:
+                                       raise template.TemplateSyntaxError('"%s" template tag option "as" requires an argument specifying a variable name' % tag)
+                       else: # node
+                               node = option_token
+               return NodeURLNode(node=node, with_obj=with_obj, as_var=as_var)
+       else:
+               raise template.TemplateSyntaxError('"%s" template tag cannot accept more than five arguments' % tag)
\ No newline at end of file