From caad74ead0bc642fdb6406148be83232b5653b51 Mon Sep 17 00:00:00 2001 From: zbyte64 Date: Mon, 4 Aug 2008 23:08:57 -0400 Subject: [PATCH] Render specific blocks from templates (useful for AJAX, alternative) Special thanks to the author of snippet 769 who provided most of the code for this snippet. Major differences: 1.Simpler/better handling of "extends" block tag 2.Searches If/Else blocks 3.Less code 4.Allow list of templates to be passed which is closer to the behavior of render_to_response --- template.py | 77 ++++++++++++++++++----------------------------------- 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/template.py b/template.py index 9d0777d..3895b7d 100644 --- a/template.py +++ b/template.py @@ -1,62 +1,37 @@ -# file template.py - -import new from django.template.loader_tags import BlockNode, ExtendsNode from django.template import loader, Context, RequestContext, TextNode +def get_template(template): + if isinstance(template, (tuple, list)): + return loader.select_template(template) + return loader.get_template(template) + class BlockNotFound(Exception): pass -class ExtendsNodeMixin(object): - def compile(self, context): - """ - Compiles this node and returns the compiled parent. - """ - compiled_parent = self.get_parent(context) - pos = 0 - while isinstance(compiled_parent.nodelist[pos], TextNode): - pos += 1 - parent_is_child = isinstance(compiled_parent.nodelist[pos], ExtendsNode) - parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)]) - for block_node in self.nodelist.get_nodes_by_type(BlockNode): - # Check for a BlockNode with this node's name, and replace it if found. - try: - parent_block = parent_blocks[block_node.name] - except KeyError: - # This BlockNode wasn't found in the parent template, but the - # parent block might be defined in the parent's *parent*, so we - # add this BlockNode to the parent's ExtendsNode nodelist, so - # it'll be checked when the parent node's render() is called. - if parent_is_child: - compiled_parent.nodelist[pos].nodelist.append(block_node) - else: - # Keep any existing parents and add a new one. Used by BlockNode. - parent_block.parent = block_node.parent - parent_block.add_parent(parent_block.nodelist) - parent_block.nodelist = block_node.nodelist - return compiled_parent - -ExtendsNode.__bases__ += (ExtendsNodeMixin,) - -def render(self, context): - self.compiled_parent = self.compile(context) - return self.compiled_parent.render(context) - -ExtendsNode.render = new.instancemethod(render, None, ExtendsNode) - def render_template_block(template, block, context): """ Renders a single block from a template. This template should have previously been rendered. """ - if len(template.nodelist) and not isinstance(template.nodelist[0], ExtendsNode): - for blk in template.nodelist: - if isinstance(blk, BlockNode) and blk.name == block: - return blk.render(context) - raise BlockNotFound - for blk in template.nodelist[0].nodelist: - if isinstance(blk, BlockNode) and blk.name == block: - return blk.render(context) - return render_template_block(template.nodelist[0].compiled_parent, block, context) + return render_template_block_nodelist(template.nodelist, block, context) + +def render_template_block_nodelist(nodelist, block, context): + for node in nodelist: + if isinstance(node, BlockNode) and node.name == block: + return node.render(context) + for key in ('nodelist', 'nodelist_true', 'nodelist_false'): + if hasattr(node, key): + try: + return render_template_block_nodelist(getattr(node, key), block, context) + except: + pass + for node in nodelist: + if isinstance(node, ExtendsNode): + try: + return render_template_block(node.get_parent(context), block, context) + except BlockNotFound: + pass + raise BlockNotFound def render_block_to_string(template_name, block, dictionary=None, context_instance=None): """ @@ -64,7 +39,7 @@ def render_block_to_string(template_name, block, dictionary=None, context_instan context. Returns a string. """ dictionary = dictionary or {} - t = loader.get_template(template_name) + t = get_template(template_name) if context_instance: context_instance.update(dictionary) else: @@ -86,6 +61,6 @@ def direct_block_to_template(request, template, block, extra_context=None, mimet else: dictionary[key] = value c = RequestContext(request, dictionary) - t = loader.get_template(template) + t = get_template(template) t.render(c) return HttpResponse(render_template_block(t, block, c), mimetype=mimetype)