Initial embed commit. Implements TemplateField and EmbedField - model fields that...
[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
5
6 register = template.Library()
7
8
9 class EmbedNode(template.Node):
10         def __init__(self, model, varname, object_pk=None, template_name=None):
11                 assert template_name is not None or object_pk is not None
12                 
13                 app_label, model = model.split('.')
14                 self.model = ContentType.objects.get(app_label=app_label, model=model).model_class()
15                 self.varname = varname
16                 self.object_pk = object_pk
17                 self.template_name = template_name
18         
19         def render(self, context):
20                 if self.template_name is not None:
21                         template_name = self.template_name.resolve(context)
22                 
23                         try:
24                                 t = template.loader.get_template(template_name)
25                         except template.TemplateDoesNotExist:
26                                 return settings.TEMPLATE_STRING_IF_INVALID
27                         else:
28                                 if self.varname not in context:
29                                         context[self.varname] = {}
30                                 context[self.varname][self.model] = t
31                         return ''
32                 
33                 # Otherwise self.object_pk is set. Render the instance with the appropriate template!
34                 try:
35                         instance = self.model.objects.get(pk=self.object_pk.resolve(context))
36                 except self.model.DoesNotExist:
37                         return settings.TEMPLATE_STRING_IF_INVALID
38                 
39                 try:
40                         t = context[self.varname][self.model]
41                 except KeyError:
42                         return settings.TEMPLATE_STRING_IF_INVALID
43                 
44                 context.push()
45                 context['embedded'] = instance
46                 t_rendered = t.render(context)
47                 context.pop()
48                 return t_rendered
49
50
51 def do_embed(parser, token):
52         """
53         The {% embed %} tag can be used in three ways:
54         {% embed as <varname> %} :: This sets which variable will be used to track embedding template names for the current context. Default: "embed"
55         {% embed <app_label>.<model_name> with <template> %} :: Sets which template will be used to render a particular model.
56         {% embed <app_label>.<model_name> <object_pk> %} :: Embeds the instance specified by the given parameters in the document with the previously-specified template.
57         """
58         args = token.split_contents()
59         tag = args[0]
60         
61         if len(args) < 2:
62                 raise template.TemplateSyntaxError('"%s" template tag must have at least three arguments.' % tag)
63         elif len(args) > 4:
64                 raise template.TemplateSyntaxError('"%s" template tag may have no more than four arguments.' % tag)
65         else:
66                 if len(args) == 3 and args[1] == "as":
67                         parser._embedNodeVarName = args[2]
68                         return template.defaulttags.CommentNode()
69                 
70                 if '.' not in args[1]:
71                         raise template.TemplateSyntaxError('"%s" template tag expects the first argument to be of the type app_label.model' % tag)
72                 
73                 if len(args) == 3:
74                         return EmbedNode(args[1], object_pk=args[2], varname=getattr(parser, '_embedNodeVarName', 'embed'))
75                 else:
76                         # 3 args
77                         if args[2] != "with":
78                                 raise template.TemplateSyntaxError('"%s" template tag requires the second of three arguments to be "with"' % tag)
79                         
80                         if args[3][0] not in ['"', "'"] and args[3][-1] not in ['"', "'"]:
81                                 raise template.TemplateSyntaxError('"%s" template tag expects the template name to be in quotes.' % tag)
82                         if args[3][0] != args[3][-1]:
83                                 raise template.TemplateSyntaxError('"%s" template tag called with non-matching quotes.' % tag)
84                         
85                         template_name = args[3].strip('"\'')
86                         
87                         return EmbedNode(args[1], template_name=template_name, varname=getattr(parser, '_embedNodeVarName', 'embed'))
88
89
90 register.tag('embed', do_embed)