722f2d8d17222771b4cb1256179f865c52a2deae
[philo.git] / philo / templatetags / containers.py
1 """
2 The container template tags are automatically included as builtins if :mod:`philo` is an installed app.
3
4 .. templatetag:: container
5
6 container
7 ---------
8
9 If a template using this tag is used to render a :class:`.Page`, that :class:`.Page` will have associated content which can be set in the admin interface. If a content type is referenced, then a :class:`.ContentReference` object will be created; otherwise, a :class:`.Contentlet` object will be created.
10
11 Usage::
12
13         {% container <name> [[references <app_label>.<model_name>] as <variable>] %}
14
15 """
16
17 from django import template
18 from django.conf import settings
19 from django.contrib.contenttypes.models import ContentType
20 from django.core.exceptions import ObjectDoesNotExist
21 from django.utils.safestring import SafeUnicode, mark_safe
22
23
24 register = template.Library()
25
26
27 class ContainerNode(template.Node):
28         def __init__(self, name, references=None, as_var=None):
29                 self.name = name
30                 self.as_var = as_var
31                 self.references = references
32         
33         def render(self, context):
34                 content = settings.TEMPLATE_STRING_IF_INVALID
35                 if 'page' in context:
36                         container_content = self.get_container_content(context)
37                 else:
38                         container_content = None
39                 
40                 if self.as_var:
41                         context[self.as_var] = container_content
42                         return ''
43                 
44                 if not container_content:
45                         return ''
46                 
47                 return container_content
48         
49         def get_container_content(self, context):
50                 page = context['page']
51                 if self.references:
52                         # Then it's a content reference.
53                         try:
54                                 contentreference = page.contentreferences.get(name__exact=self.name, content_type=self.references)
55                                 content = contentreference.content
56                         except ObjectDoesNotExist:
57                                 content = ''
58                 else:
59                         # Otherwise it's a contentlet.
60                         try:
61                                 contentlet = page.contentlets.get(name__exact=self.name)
62                                 if '{%' in contentlet.content or '{{' in contentlet.content:
63                                         try:
64                                                 content = template.Template(contentlet.content, name=contentlet.name).render(context)
65                                         except template.TemplateSyntaxError, error:
66                                                 if settings.DEBUG:
67                                                         content = ('[Error parsing contentlet \'%s\': %s]' % (self.name, error))
68                                                 else:
69                                                         content = settings.TEMPLATE_STRING_IF_INVALID
70                                 else:
71                                         content = contentlet.content
72                         except ObjectDoesNotExist:
73                                 content = settings.TEMPLATE_STRING_IF_INVALID
74                         content = mark_safe(content)
75                 return content
76
77
78 def do_container(parser, token):
79         """
80         {% container <name> [[references <app_label>.<model_name>] as <variable>] %}
81         
82         """
83         params = token.split_contents()
84         if len(params) >= 2:
85                 tag = params[0]
86                 name = params[1].strip('"')
87                 references = None
88                 as_var = None
89                 if len(params) > 2:
90                         remaining_tokens = params[2:]
91                         while remaining_tokens:
92                                 option_token = remaining_tokens.pop(0)
93                                 if option_token == 'references':
94                                         try:
95                                                 app_label, model = remaining_tokens.pop(0).strip('"').split('.')
96                                                 references = ContentType.objects.get(app_label=app_label, model=model)
97                                         except IndexError:
98                                                 raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument specifying a content type' % tag)
99                                         except ValueError:
100                                                 raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument of the form app_label.model (see django.contrib.contenttypes)' % tag)
101                                         except ObjectDoesNotExist:
102                                                 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)
103                                 elif option_token == 'as':
104                                         try:
105                                                 as_var = remaining_tokens.pop(0)
106                                         except IndexError:
107                                                 raise template.TemplateSyntaxError('"%s" template tag option "as" requires an argument specifying a variable name' % tag)
108                         if references and not as_var:
109                                 raise template.TemplateSyntaxError('"%s" template tags using "references" option require additional use of the "as" option specifying a variable name' % tag)
110                 return ContainerNode(name, references, as_var)
111                 
112         else: # error
113                 raise template.TemplateSyntaxError('"%s" template tag provided without arguments (at least one required)' % tag)
114
115
116 register.tag('container', do_container)