Adjusted to match the new master TemplateField changes. Switched the setting of _embe...
[philo.git] / contrib / penfield / templatetags / embed.py
1 from django import template
2 from django.contrib.contenttypes.models import ContentType
3 from django.conf import settings
4 from philo.utils import LOADED_TEMPLATE_ATTR
5
6
7 register = template.Library()
8
9
10 class EmbedNode(template.Node):
11         def __init__(self, content_type, varname, object_pk=None, template_name=None):
12                 assert template_name is not None or object_pk is not None
13                 self.content_type = content_type
14                 self.varname = varname
15                 
16                 if object_pk is not None:
17                         self.object_pk = object_pk
18                         try:
19                                 self.instance = content_type.get_object_for_this_type(pk=object_pk)
20                         except content_type.model_class().DoesNotExist:
21                                 self.instance = False
22                 else:
23                         self.instance = None
24                 
25                 if template_name is not None:
26                         try:
27                                 self.template = template.loader.get_template(template_name)
28                         except template.TemplateDoesNotExist:
29                                 self.template = False
30                 else:
31                         self.template = None
32         
33         def render(self, context):
34                 if self.template_name is not None:
35                         if self.template is False:
36                                 return settings.TEMPLATE_STRING_IF_INVALID
37                         
38                         if self.varname not in context:
39                                 context[self.varname] = {}
40                         context[self.varname][self.content_type] = self.template
41                         
42                         return ''
43                 
44                 # Otherwise self.instance should be set. Render the instance with the appropriate template!
45                 if self.instance is None or self.instance is False:
46                         return settings.TEMPLATE_STRING_IF_INVALID
47                 
48                 try:
49                         t = context[self.varname][self.content_type]
50                 except KeyError:
51                         return settings.TEMPLATE_STRING_IF_INVALID
52                 
53                 context.push()
54                 context['embedded'] = self.instance
55                 t_rendered = t.render(context)
56                 context.pop()
57                 return t_rendered
58
59
60 def get_embedded(self):
61         return template.loader.get_template(self.template_name)
62
63
64 setattr(EmbedNode, LOADED_TEMPLATE_ATTR, property(get_embedded))
65
66
67 def do_embed(parser, token):
68         """
69         The {% embed %} tag can be used in three ways:
70         {% embed as <varname> %} :: This sets which variable will be used to track embedding template names for the current context. Default: "embed"
71         {% embed <app_label>.<model_name> with <template> %} :: Sets which template will be used to render a particular model.
72         {% embed <app_label>.<model_name> <object_pk> %} :: Embeds the instance specified by the given parameters in the document with the previously-specified template.
73         """
74         args = token.split_contents()
75         tag = args[0]
76         
77         if len(args) < 2:
78                 raise template.TemplateSyntaxError('"%s" template tag must have at least three arguments.' % tag)
79         elif len(args) > 4:
80                 raise template.TemplateSyntaxError('"%s" template tag may have no more than four arguments.' % tag)
81         else:
82                 if len(args) == 3 and args[1] == "as":
83                         parser._embedNodeVarName = args[2]
84                         return template.defaulttags.CommentNode()
85                 
86                 if '.' not in args[1]:
87                         raise template.TemplateSyntaxError('"%s" template tag expects the first argument to be of the form app_label.model' % tag)
88                 
89                 app_label, model = args[1].split('.')
90                 try:
91                         ct = ContentType.objects.get(app_label=app_label, model=model)
92                 except ContentType.DoesNotExist:
93                         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)
94                 
95                 if len(args) == 3:
96                         
97                         return EmbedNode(ct, object_pk=args[2], varname=getattr(parser, '_embedNodeVarName', 'embed'))
98                 else:
99                         # 3 args
100                         if args[2] != "with":
101                                 raise template.TemplateSyntaxError('"%s" template tag requires the second of three arguments to be "with"' % tag)
102                         
103                         if args[3][0] not in ['"', "'"] and args[3][-1] not in ['"', "'"]:
104                                 raise template.TemplateSyntaxError('"%s" template tag expects the template name to be in quotes.' % tag)
105                         if args[3][0] != args[3][-1]:
106                                 raise template.TemplateSyntaxError('"%s" template tag called with non-matching quotes.' % tag)
107                         
108                         template_name = args[3].strip('"\'')
109                         
110                         return EmbedNode(ct, template_name=template_name, varname=getattr(parser, '_embedNodeVarName', 'embed'))
111
112
113 register.tag('embed', do_embed)