X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/e5b488ac6b676cbac24eb5f5717f0ad071ce2957..f314a8ddceb543e2bb4711d50bdd2060452689b1:/templatetags/embed.py diff --git a/templatetags/embed.py b/templatetags/embed.py index d7a8466..eb4cd68 100644 --- a/templatetags/embed.py +++ b/templatetags/embed.py @@ -26,7 +26,8 @@ class EmbedContext(object): """To return a template for an embed node, find the node's position in the stack and then progress up the stack until a template-defining node is found """ - embeds = self.embeds[embed.content_type] + ct = embed.get_content_type(context) + embeds = self.embeds[ct] embeds = embeds[:embeds.index(embed)][::-1] for e in embeds: template = e.get_template(context) @@ -46,7 +47,7 @@ class EmbedContext(object): else: embed_context = context_dict[EMBED_CONTEXT_KEY] # We can tell where we are in the list of embeds by which have already been rendered. - embeds = embed_context.embeds[embed.content_type][:len(embed_context.rendered)][::-1] + embeds = embed_context.embeds[ct][:len(embed_context.rendered)][::-1] for e in embeds: template = e.get_template(context) if template: @@ -60,23 +61,28 @@ class EmbedContext(object): old_extends_node_init = ExtendsNode.__init__ -def get_embed_dict(nodelist): +def get_embed_dict(embed_list, context): embeds = {} - for n in nodelist.get_nodes_by_type(ConstantEmbedNode): - if n.content_type not in embeds: - embeds[n.content_type] = [n] + for e in embed_list: + ct = e.get_content_type(context) + if ct is None: + # Then the embed doesn't exist for this context. + continue + if ct not in embeds: + embeds[ct] = [e] else: - embeds[n.content_type].append(n) + embeds[ct].append(e) return embeds def extends_node_init(self, nodelist, *args, **kwargs): - self.embeds = get_embed_dict(nodelist) + self.embed_list = nodelist.get_nodes_by_type(ConstantEmbedNode) old_extends_node_init(self, nodelist, *args, **kwargs) def render_extends_node(self, context): compiled_parent = self.get_parent(context) + embeds = get_embed_dict(self.embed_list, context) if BLOCK_CONTEXT_KEY not in context.render_context: context.render_context[BLOCK_CONTEXT_KEY] = BlockContext() @@ -89,7 +95,7 @@ def render_extends_node(self, context): # Add the block nodes from this node to the block context # Do the equivalent for embed nodes block_context.add_blocks(self.blocks) - embed_context.add_embeds(self.embeds) + embed_context.add_embeds(embeds) # If this block's parent doesn't have an extends node it is the root, # and its block nodes also need to be added to the block context. @@ -99,10 +105,16 @@ def render_extends_node(self, context): if not isinstance(node, ExtendsNode): blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)]) block_context.add_blocks(blocks) - embeds = get_embed_dict(compiled_parent.nodelist) + embeds = get_embed_dict(compiled_parent.nodelist.get_nodes_by_type(ConstantEmbedNode), context) embed_context.add_embeds(embeds) break - + + # Explicitly render all direct embed children of this node. + if self.embed_list: + for node in self.nodelist: + if isinstance(node, ConstantEmbedNode): + node.render(context) + # Call Template._render explicitly so the parser context stays # the same. return compiled_parent._render(context) @@ -133,8 +145,7 @@ class ConstantEmbedNode(template.Node): else: self.template = None - def compile_instance(self, object_pk, context=None): - self.object_pk = object_pk + def compile_instance(self, object_pk): model = self.content_type.model_class() try: return model.objects.get(pk=object_pk) @@ -147,11 +158,11 @@ class ConstantEmbedNode(template.Node): def get_instance(self, context): return self.instance - def compile_template(self, template_name, context=None): + def compile_template(self, template_name): try: return template.loader.get_template(template_name) except template.TemplateDoesNotExist: - if not hasattr(self, 'template_name') and settings.TEMPLATE_DEBUG: + if hasattr(self, 'template') and settings.TEMPLATE_DEBUG: # Then it's a constant node. raise return False @@ -159,53 +170,55 @@ class ConstantEmbedNode(template.Node): def get_template(self, context): return self.template + def get_content_type(self, context): + return self.content_type + def check_context(self, context): if EMBED_CONTEXT_KEY not in context.render_context: context.render_context[EMBED_CONTEXT_KEY] = EmbedContext() embed_context = context.render_context[EMBED_CONTEXT_KEY] - - if self.content_type not in embed_context.embeds: - embed_context.embeds[self.content_type] = [self] - elif self not in embed_context.embeds[self.content_type]: - embed_context.embeds[self.content_type].append(self) + ct = self.get_content_type(context) + if ct not in embed_context.embeds: + embed_context.embeds[ct] = [self] + elif self not in embed_context.embeds[ct]: + embed_context.embeds[ct].append(self) - def mark_rendered(self, context): + def mark_rendered_for(self, context): context.render_context[EMBED_CONTEXT_KEY].rendered.append(self) def render(self, context): self.check_context(context) - if self.template is not None: - if self.template is False: + template = self.get_template(context) + if template is not None: + self.mark_rendered_for(context) + if template is False: return settings.TEMPLATE_STRING_IF_INVALID - self.mark_rendered(context) return '' - # Otherwise self.instance should be set. Render the instance with the appropriate template! - if self.instance is None or self.instance is False: - self.mark_rendered(context) + # Otherwise an instance should be available. Render the instance with the appropriate template! + instance = self.get_instance(context) + if instance is None or instance is False: + self.mark_rendered_for(context) return settings.TEMPLATE_STRING_IF_INVALID - return self.render_instance(context, self.instance) + return self.render_instance(context, instance) def render_instance(self, context, instance): try: t = context.render_context[EMBED_CONTEXT_KEY].get_embed_template(self, context) except (KeyError, IndexError): - if settings.TEMPLATE_DEBUG: - raise + self.mark_rendered_for(context) return settings.TEMPLATE_STRING_IF_INVALID context.push() context['embedded'] = instance - kwargs = {} for k, v in self.kwargs.items(): - kwargs[k] = v.resolve(context) - context.update(kwargs) + context[k] = v.resolve(context) t_rendered = t.render(context) context.pop() - self.mark_rendered(context) + self.mark_rendered_for(context) return t_rendered @@ -213,46 +226,45 @@ class EmbedNode(ConstantEmbedNode): def __init__(self, content_type, 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 - - kwargs = kwargs or {} - for k, v in kwargs.items(): - kwargs[k] = v - self.kwargs = kwargs + self.kwargs = kwargs or {} if object_pk is not None: self.object_pk = object_pk else: self.object_pk = None - self.instance = None if template_name is not None: self.template_name = template_name else: self.template_name = None - self.template = None def get_instance(self, context): - return self.compile_instance(self.object_pk, context) + if self.object_pk is None: + return None + return self.compile_instance(self.object_pk.resolve(context)) def get_template(self, context): - return self.compile_template(self.template_name, context) + if self.template_name is None: + return None + return self.compile_template(self.template_name.resolve(context)) + + +class InstanceEmbedNode(EmbedNode): + def __init__(self, instance, kwargs=None): + self.instance = instance + self.kwargs = kwargs or {} - def render(self, context): - self.check_context(context) - - if self.template_name is not None: - self.mark_rendered(context) - return '' - - if self.object_pk is None: - if settings.TEMPLATE_DEBUG: - raise ValueError("NoneType is not a valid object_pk value") - self.mark_rendered(context) - return settings.TEMPLATE_STRING_IF_INVALID - - instance = self.compile_instance(self.object_pk.resolve(context)) - - return self.render_instance(context, instance) + def get_template(self, context): + return None + + def get_instance(self, context): + return self.instance.resolve(context) + + def get_content_type(self, context): + instance = self.get_instance(context) + if not instance: + return None + return ContentType.objects.get_for_model(instance) def get_embedded(self): @@ -262,51 +274,63 @@ def get_embedded(self): setattr(ConstantEmbedNode, LOADED_TEMPLATE_ATTR, property(get_embedded)) +def parse_content_type(bit, tagname): + try: + app_label, model = bit.split('.') + except ValueError: + raise template.TemplateSyntaxError('"%s" template tag expects the first argument to be of the form app_label.model' % tagname) + try: + ct = ContentType.objects.get(app_label=app_label, model=model) + except ContentType.DoesNotExist: + raise template.TemplateSyntaxError('"%s" template tag requires an argument of the form app_label.model which refers to an installed content type (see django.contrib.contenttypes)' % tagname) + return ct + + def do_embed(parser, token): """ The {% embed %} tag can be used in two ways: {% embed . with