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