Render specific blocks from templates (useful for AJAX, alternative)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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

def render_template_block(template, block, context):
    """
    Renders a single block from a template. This template should have previously been rendered.
    """
    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):
    """
    Loads the given template_name and renders the given block with the given dictionary as
    context. Returns a string.
    """
    dictionary = dictionary or {}
    t = get_template(template_name)
    if context_instance:
        context_instance.update(dictionary)
    else:
        context_instance = Context(dictionary)
    t.render(context_instance)
    return render_template_block(t, block, context_instance)

def direct_block_to_template(request, template, block, extra_context=None, mimetype=None, **kwargs):
    """
    Render a given block in a given template with any extra URL parameters in the context as
    ``{{ params }}``.
    """
    if extra_context is None:
    	extra_context = {}
    dictionary = {'params': kwargs}
    for key, value in extra_context.items():
        if callable(value):
            dictionary[key] = value()
        else:
            dictionary[key] = value
    c = RequestContext(request, dictionary)
    t = get_template(template)
    t.render(c)
    return HttpResponse(render_template_block(t, block, c), mimetype=mimetype)

More like this

  1. Render specific blocks from templates (useful for AJAX) by sciyoshi 5 years, 11 months ago
  2. Pygments Rendering Template Filter by ericflo 7 years, 1 month ago
  3. Template {% macro %} support, with context rendering by MattP 1 year, 2 months ago
  4. Partial JSON template rendering by barbuza 6 years, 5 months ago
  5. Markdown and Syntax Highlighting in Django by blinks 7 years, 1 month ago

Comments

bcurtu (on September 4, 2008):

Please,

May you add some documentation and examples?

Thanx

#

cornbread (on December 1, 2008):

Example would be great!

#

chadselph (on August 27, 2010):

This is an outstanding snippet and I'd vote for it to be included into core, but there's a pointless .render() on line 47, presumably left over from debugging.

This is actually a bug because if the entire template requires a variable and the block does not, render_block_to_string will fail without that unnecessary variable.

#

eugenyboger (on January 10, 2011):

in django 1.3 there is a problem with nested extends.

To fix: comment out line 47 with "t.render(context_instance" and add "template._render(context)" after line 15.

Seems like it helps. Still not sure why exactly it does.

#

jtheoof (on January 10, 2011):

Really useful snippet, I use it for all my AJAX template rendering code. I just edited function render_block_to_string with

def render_block_to_string(template_name, block, dictionary=None, context_instance=None):
    """
    Loads the given template_name and renders the given block with the given dictionary as
    context. Returns a string.
    """
    import re

    dictionary = dictionary or {}
    t = get_template(template_name)
    if context_instance:
        context_instance.update(dictionary)
    else:
        context_instance = Context(dictionary)
    template_block = render_template_block(t, block, context_instance)
    return re.sub(r'\s+', ' ', template_block)

Not the regex at the end to avoid unnecessary space characters to be sent over the network.

#

(Forgotten your password?)