Removed referential integrity code. Moved embed templatetag into core. Differentiated...
[philo.git] / templatetags / embed.py
similarity index 59%
rename from contrib/penfield/templatetags/embed.py
rename to templatetags/embed.py
index 7d1b26a..c0fcff0 100644 (file)
@@ -7,7 +7,8 @@ from philo.utils import LOADED_TEMPLATE_ATTR
 register = template.Library()
 
 
-class EmbedNode(template.Node):
+class ConstantEmbedNode(template.Node):
+       """Analogous to the ConstantIncludeNode, this node precompiles several variables necessary for correct rendering - namely the referenced instance or the included template."""
        def __init__(self, content_type, varname, object_pk=None, template_name=None, kwargs=None):
                assert template_name is not None or object_pk is not None
                self.content_type = content_type
@@ -19,24 +20,35 @@ class EmbedNode(template.Node):
                self.kwargs = kwargs
                
                if object_pk is not None:
-                       self.object_pk = object_pk
-                       try:
-                               self.instance = content_type.get_object_for_this_type(pk=object_pk)
-                       except content_type.model_class().DoesNotExist:
-                               self.instance = False
+                       self.compile_instance(object_pk)
+                       if self.instance is False and settings.TEMPLATE_DEBUG:
+                               raise
                else:
                        self.instance = None
                
                if template_name is not None:
-                       try:
-                               self.template = template.loader.get_template(template_name)
-                       except template.TemplateDoesNotExist:
-                               self.template = False
+                       self.compile_template(template_name[1:-1])
+                       if self.template is False and settings.TEMPLATE_DEBUG:
+                               raise
                else:
                        self.template = None
        
+       def compile_instance(self, object_pk):
+               self.object_pk = object_pk
+               model = self.content_type.model_class()
+               try:
+                       self.instance = model.objects.get(pk=object_pk)
+               except model.DoesNotExist:
+                       self.instance = False
+       
+       def compile_template(self, template_name):
+               try:
+                       self.template = template.loader.get_template(template_name)
+               except template.TemplateDoesNotExist:
+                       self.template = False
+       
        def render(self, context):
-               if self.template_name is not None:
+               if self.template is not None:
                        if self.template is False:
                                return settings.TEMPLATE_STRING_IF_INVALID
                        
@@ -50,26 +62,65 @@ class EmbedNode(template.Node):
                if self.instance is None or self.instance is False:
                        return settings.TEMPLATE_STRING_IF_INVALID
                
+               return self.render_template(context, self.instance)
+       
+       def render_template(self, context, instance):
                try:
                        t = context[self.varname][self.content_type]
                except KeyError:
                        return settings.TEMPLATE_STRING_IF_INVALID
                
                context.push()
-               context['embedded'] = self.instance
+               context['embedded'] = instance
+               kwargs = {}
                for k, v in self.kwargs.items():
-                       self.kwargs[k] = v.resolve(context)
-               context.update(self.kwargs)
+                       kwargs[k] = v.resolve(context)
+               context.update(kwargs)
                t_rendered = t.render(context)
                context.pop()
                return t_rendered
 
 
+class EmbedNode(ConstantEmbedNode):
+       def __init__(self, content_type, varname, object_pk=None, template_name=None, kwargs=None):
+               assert template_name is not None or object_pk is not None
+               self.content_type = content_type
+               self.varname = varname
+               
+               kwargs = kwargs or {}
+               for k, v in kwargs.items():
+                       kwargs[k] = template.Variable(v)
+               self.kwargs = kwargs
+               
+               if object_pk is not None:
+                       self.object_pk = template.Variable(object_pk)
+               else:
+                       self.object_pk = None
+                       self.instance = None
+               
+               if template_name is not None:
+                       self.template_name = template.Variable(template_name)
+               else:
+                       self.template_name = None
+                       self.template = None
+       
+       def render(self, context):
+               if self.template_name is not None:
+                       template_name = self.template_name.resolve(context)
+                       self.compile_template(template_name)
+               
+               if self.object_pk is not None:
+                       object_pk = self.object_pk.resolve(context)
+                       self.compile_instance(object_pk)
+               
+               return super(EmbedNode, self).render(context)
+
+
 def get_embedded(self):
-       return template.loader.get_template(self.template_name)
+       return self.template
 
 
-setattr(EmbedNode, LOADED_TEMPLATE_ATTR, property(get_embedded))
+setattr(ConstantEmbedNode, LOADED_TEMPLATE_ATTR, property(get_embedded))
 
 
 def do_embed(parser, token):
@@ -97,21 +148,18 @@ def do_embed(parser, token):
                except ContentType.DoesNotExist:
                        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)
                
+               varname = getattr(parser, '_embedNodeVarName', 'embed')
+               
                if args[2] == "with":
                        if len(args) > 4:
                                raise template.TemplateSyntaxError('"%s" template tag may have no more than four arguments.' % tag)
                        
-                       if args[3][0] not in ['"', "'"] and args[3][-1] not in ['"', "'"]:
-                               raise template.TemplateSyntaxError('"%s" template tag expects the template name to be in quotes.' % tag)
-                       if args[3][0] != args[3][-1]:
-                               raise template.TemplateSyntaxError('"%s" template tag called with non-matching quotes.' % tag)
+                       if args[3][0] in ['"', "'"] and args[3][0] == args[3][-1]:
+                               return ConstantEmbedNode(ct, template_name=args[3], varname=varname)
                        
-                       template_name = args[3].strip('"\'')
-                       
-                       return EmbedNode(ct, template_name=template_name, varname=getattr(parser, '_embedNodeVarName', 'embed'))
-               object_pk = args[2]
-               varname = getattr(parser, '_embedNodeVarName', 'embed')
+                       return EmbedNode(ct, template_name=args[3], varname=varname)
                
+               object_pk = args[2]
                remaining_args = args[3:]
                kwargs = {}
                for arg in remaining_args: