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