Added docs for the db template loader and skeleton docs for templatetags. Updated...
[philo.git] / philo / templatetags / nodes.py
1 from django import template
2 from django.conf import settings
3 from django.contrib.sites.models import Site
4 from django.core.urlresolvers import reverse, NoReverseMatch
5 from django.template.defaulttags import kwarg_re
6 from django.utils.encoding import smart_str
7
8 from philo.exceptions import ViewCanNotProvideSubpath
9
10
11 register = template.Library()
12
13
14 class NodeURLNode(template.Node):
15         def __init__(self, node, as_var, with_obj=None, view_name=None, args=None, kwargs=None):
16                 self.as_var = as_var
17                 self.view_name = view_name
18                 
19                 # Because the following variables have already been compiled as filters if they exist, they don't need to be re-scanned as template variables.
20                 self.node = node
21                 self.with_obj = with_obj
22                 self.args = args
23                 self.kwargs = kwargs
24         
25         def render(self, context):
26                 if self.node:
27                         node = self.node.resolve(context)
28                 else:
29                         node = context.get('node', None)
30                 
31                 if not node:
32                         return settings.TEMPLATE_STRING_IF_INVALID
33                 
34                 if self.with_obj is None and self.view_name is None:
35                         url = node.get_absolute_url()
36                 else:
37                         if not node.view.accepts_subpath:
38                                 return settings.TEMPLATE_STRING_IF_INVALID
39                         
40                         if self.with_obj is not None:
41                                 try:
42                                         view_name, args, kwargs = node.view.get_reverse_params(self.with_obj.resolve(context))
43                                 except ViewCanNotProvideSubpath:
44                                         return settings.TEMPLATE_STRING_IF_INVALID
45                         else: # self.view_name is not None
46                                 view_name = self.view_name
47                                 args = [arg.resolve(context) for arg in self.args]
48                                 kwargs = dict([(smart_str(k, 'ascii'), v.resolve(context)) for k, v in self.kwargs.items()])
49                         
50                         url = ''
51                         try:
52                                 subpath = reverse(view_name, urlconf=node.view, args=args, kwargs=kwargs)
53                         except NoReverseMatch:
54                                 if self.as_var is None:
55                                         if settings.TEMPLATE_DEBUG:
56                                                 raise
57                                         return settings.TEMPLATE_STRING_IF_INVALID
58                         else:
59                                 url = node.construct_url(subpath)
60                 
61                 if self.as_var:
62                         context[self.as_var] = url
63                         return ''
64                 else:
65                         return url
66
67
68 @register.tag(name='node_url')
69 def do_node_url(parser, token):
70         """
71         Usage::
72         
73                 {% node_url [for <node>] [as <var>] %}
74                 {% node_url with <obj> [for <node>] [as <var>] %}
75                 {% node_url <view_name> [<arg1> [<arg2> ...] ] [for <node>] [as <var>] %}
76                 {% node_url <view_name> [<key1>=<value1> [<key2>=<value2> ...] ] [for <node>] [as <var>] %}
77         
78         """
79         params = token.split_contents()
80         tag = params[0]
81         as_var = None
82         with_obj = None
83         node = None
84         params = params[1:]
85         
86         if len(params) >= 2 and params[-2] == 'as':
87                 as_var = params[-1]
88                 params = params[:-2]
89         
90         if len(params) >= 2 and params[-2] == 'for':
91                 node = parser.compile_filter(params[-1])
92                 params = params[:-2]
93         
94         if len(params) >= 2 and params[-2] == 'with':
95                 with_obj = parser.compile_filter(params[-1])
96                 params = params[:-2]
97         
98         if with_obj is not None:
99                 if params:
100                         raise template.TemplateSyntaxError('`%s` template tag accepts no arguments or keyword arguments if with <obj> is specified.' % tag)
101                 return NodeURLNode(with_obj=with_obj, node=node, as_var=as_var)
102         
103         if params:
104                 args = []
105                 kwargs = {}
106                 view_name = params.pop(0)
107                 for param in params:
108                         match = kwarg_re.match(param)
109                         if not match:
110                                 raise TemplateSyntaxError("Malformed arguments to `%s` tag" % tag)
111                         name, value = match.groups()
112                         if name:
113                                 kwargs[name] = parser.compile_filter(value)
114                         else:
115                                 args.append(parser.compile_filter(value))
116                 return NodeURLNode(view_name=view_name, args=args, kwargs=kwargs, node=node, as_var=as_var)
117         
118         return NodeURLNode(node=node, as_var=as_var)