MultiViews now clear_url_caches before resolving URLs, needed to allow them to change...
[philo.git] / templatetags / containers.py
1 from django import template
2 from django.conf import settings
3 from django.utils.safestring import SafeUnicode, mark_safe
4 from django.core.exceptions import ObjectDoesNotExist
5 from django.contrib.contenttypes.models import ContentType
6
7
8 register = template.Library()
9
10
11 class ContainerNode(template.Node):
12         child_nodelists = ('nodelist_main', 'nodelist_empty',)
13         
14         def __init__(self, name, references=None, as_var=None, nodelist_main=None, nodelist_empty=None):
15                 self.name = name
16                 self.as_var = as_var
17                 self.references = references
18                 
19                 if nodelist_main is None:
20                         self.nodelist_main = template.NodeList()
21                 else:
22                         self.nodelist_main = nodelist_main
23                 
24                 if nodelist_empty is None:
25                         self.nodelist_empty = template.NodeList()
26                 else:
27                         self.nodelist_empty = nodelist_empty
28         
29         def render(self, context):
30                 content = settings.TEMPLATE_STRING_IF_INVALID
31                 if 'page' in context:
32                         container_content = self.get_container_content(context)
33                 
34                 if not self.nodelist_main:
35                         if self.as_var:
36                                 context[self.as_var] = container_content
37                                 return ''
38                         
39                         if not container_content:
40                                 return ''
41                         
42                         return container_content
43                 
44                 if container_content:
45                         if self.as_var is None:
46                                 self.as_var = self.name
47                         
48                         #make a new context 
49                         context.push()
50                         context[self.as_var] = container_content
51                         nodelist = template.NodeList()
52                         for node in self.nodelist_main:
53                                 nodelist.append(node.render(context))
54                         context.pop()
55                         return nodelist.render(context)
56                 
57                 if self.nodelist_empty is not None:
58                         return self.nodelist_empty.render(context)
59                 
60                 return ''
61         
62         def get_container_content(self, context):
63                 page = context['page']
64                 if self.references:
65                         try:
66                                 contentreference = page.contentreferences.get(name__exact=self.name, content_type=self.references)
67                                 content = contentreference.content
68                         except ObjectDoesNotExist:
69                                 content = ''
70                 else:
71                         try:
72                                 contentlet = page.contentlets.get(name__exact=self.name)
73                                 if contentlet.dynamic:
74                                         try:
75                                                 content = mark_safe(template.Template(contentlet.content, name=contentlet.name).render(context))
76                                         except template.TemplateSyntaxError, error:
77                                                 if settings.DEBUG:
78                                                         content = ('[Error parsing contentlet \'%s\': %s]' % (self.name, error))
79                                 else:
80                                         content = contentlet.content
81                         except ObjectDoesNotExist:
82                                 content = ''
83                 return content
84
85
86 def do_container(parser, token):
87         """
88         {% container <name> [[references <type>] as <variable>] %} 
89         {% blockcontainer <name> [[references <type>] as <variable>] %} [ {% empty %} ] {% endblockcontainer %}
90         """
91         params = token.split_contents()
92         if len(params) >= 2:
93                 tag = params[0]
94                 name = params[1].strip('"')
95                 references = None
96                 as_var = None
97                 if len(params) > 2:
98                         remaining_tokens = params[2:]
99                         while remaining_tokens:
100                                 option_token = remaining_tokens.pop(0)
101                                 if option_token == 'references':
102                                         try:
103                                                 app_label, model = remaining_tokens.pop(0).strip('"').split('.')
104                                                 references = ContentType.objects.get(app_label=app_label, model=model)
105                                         except IndexError:
106                                                 raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument specifying a content type' % tag)
107                                         except ValueError:
108                                                 raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument of the form app_label.model (see django.contrib.contenttypes)' % tag)
109                                         except ObjectDoesNotExist:
110                                                 raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument of the form app_label.model which refers to an installed content type (see django.contrib.contenttypes)' % tag)
111                                 elif option_token == 'as':
112                                         try:
113                                                 as_var = remaining_tokens.pop(0)
114                                         except IndexError:
115                                                 raise template.TemplateSyntaxError('"%s" template tag option "as" requires an argument specifying a variable name' % tag)
116                         if references and not as_var:
117                                 raise template.TemplateSyntaxError('"%s" template tags using "references" option require additional use of the "as" option specifying a variable name' % tag)
118                 if tag == 'container':
119                         return ContainerNode(name, references, as_var)
120                 
121                 nodelist_main = parser.parse(('empty','endblockcontainer',))
122                 token = parser.next_token()
123                 
124                 if token.contents == 'empty':
125                         nodelist_empty = parser.parse(('endblockcontainer',))
126                         parser.delete_first_token()
127                 else:
128                         nodelist_empty = None
129                 return ContainerNode(name, references, as_var, nodelist_main, nodelist_empty)
130                 
131         else: # error
132                 raise template.TemplateSyntaxError('"%s" template tag provided without arguments (at least one required)' % tag)
133
134
135 register.tag('container', do_container)
136 register.tag('blockcontainer', do_container)