2 The container template tags are automatically included as builtins if :mod:`philo` is an installed app.
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.db.models import Q
11 from django.utils.safestring import SafeUnicode, mark_safe
14 register = template.Library()
17 CONTAINER_CONTEXT_KEY = 'philo_container_context'
20 class ContainerContext(object):
21 def __init__(self, page):
22 contentlet_specs, contentreference_specs = page.template.containers
24 contentlets = page.contentlets.filter(name__in=contentlet_specs)
25 self.contentlets = dict(((c.name, c) for c in contentlets))
28 for name, ct in contentreference_specs.items():
29 q |= Q(name=name, content_type=ct)
30 references = page.contentreferences.filter(q)
31 self.references = dict(((c.name, c) for c in references))
34 class ContainerNode(template.Node):
35 def __init__(self, name, references=None, as_var=None):
38 self.references = references
40 def render(self, context):
41 content = settings.TEMPLATE_STRING_IF_INVALID
43 container_content = self.get_container_content(context)
45 container_content = None
48 context[self.as_var] = container_content
51 if not container_content:
54 return container_content
56 def get_container_content(self, context):
58 container_context = context.render_context[CONTAINER_CONTEXT_KEY]
60 container_context = ContainerContext(context['page'])
61 context.render_context[CONTAINER_CONTEXT_KEY] = container_context
64 # Then it's a content reference.
66 contentreference = container_context.references[(self.name, self.references)]
70 content = contentreference.content
72 # Otherwise it's a contentlet.
74 contentlet = container_context.contentlets[self.name]
78 content = contentlet.content
80 if '{%' in content or '{{' in content:
82 content = template.Template(contentlet.content, name=contentlet.name).render(context)
83 except template.TemplateSyntaxError, e:
85 content = ('[Error parsing contentlet \'%s\': %s]' % (self.name, e))
87 content = settings.TEMPLATE_STRING_IF_INVALID
88 content = mark_safe(content)
93 def container(parser, token):
95 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.
99 {% container <name> [[references <app_label>.<model_name>] as <variable>] %}
102 params = token.split_contents()
105 name = params[1].strip('"')
109 remaining_tokens = params[2:]
110 while remaining_tokens:
111 option_token = remaining_tokens.pop(0)
112 if option_token == 'references':
114 app_label, model = remaining_tokens.pop(0).strip('"').split('.')
115 references = ContentType.objects.get_by_natural_key(app_label, model)
117 raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument specifying a content type' % tag)
119 raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument of the form app_label.model (see django.contrib.contenttypes)' % tag)
120 except ObjectDoesNotExist:
121 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)
122 elif option_token == 'as':
124 as_var = remaining_tokens.pop(0)
126 raise template.TemplateSyntaxError('"%s" template tag option "as" requires an argument specifying a variable name' % tag)
127 if references and not as_var:
128 raise template.TemplateSyntaxError('"%s" template tags using "references" option require additional use of the "as" option specifying a variable name' % tag)
129 return ContainerNode(name, references, as_var)
132 raise template.TemplateSyntaxError('"%s" template tag provided without arguments (at least one required)' % tag)