-
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Render specific blocks from templates (useful for AJAX)
- Loading branch information
Showing
10 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/usr/bin/env python | ||
import os | ||
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings' | ||
|
||
from django.core import management | ||
|
||
if __name__ == "__main__": | ||
management.execute_from_command_line() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Install the current directory as an editable package. Denpendencies required | ||
# for installing the package and running unit tests are defined in setup.py. | ||
-e . | ||
|
||
# Not tested with older versions of Django. | ||
Django==1.1.4 # Actually 0.96, but this is the oldest on pypi. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# file template.py | ||
|
||
import new | ||
from django.template.loader_tags import BlockNode, ExtendsNode | ||
from django.template import loader, Context, RequestContext, TextNode | ||
|
||
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) | ||
|
||
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 = loader.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 = loader.get_template(template) | ||
t.render(c) | ||
return HttpResponse(render_template_block(t, block, c), mimetype=mimetype) |
File renamed without changes.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
SECRET_KEY = 'not_empty' | ||
SITE_ID = 1 | ||
|
||
DATABASE_ENGINE = 'sqlite3', | ||
|
||
MIDDLEWARE_CLASSES = tuple() | ||
|
||
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' | ||
|
||
INSTALLED_APPS = ( | ||
'tests', | ||
) | ||
AUTHENTICATION_BACKENDS = ( | ||
'django.contrib.auth.backends.ModelBackend', | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{% block block1 %}block1 from test1{% endblock %} | ||
{% block block2 %}block2 from test1{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{% extends 'test1.html' %} | ||
{% block block1 %}block1 from test1{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from unittest import TestCase | ||
|
||
from django.template import loader, Context | ||
|
||
from template import render_block_to_string | ||
|
||
|
||
class TestCases(TestCase): | ||
def test_1(self): | ||
result = render_block_to_string('test2.html', 'block1', Context({})) | ||
self.assertEqual(result, u'block1 from test2') | ||
|
||
def test_2(self): | ||
result = render_block_to_string('test2.html', 'block2', Context({})) | ||
self.assertEqual(result, u'block2 from test1') |