Skip to content

Commit

Permalink
Merge pull request #3 from clokep/jinja2
Browse files Browse the repository at this point in the history
Initial support for Jinja2.
  • Loading branch information
clokep authored Jun 17, 2016
2 parents c7a3ec0 + af14d98 commit c78a518
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 5 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
Changelog
#########

0.4 (xxxx)
==========

* Initial support for using the `Jinja2 <http://jinja.pocoo.org/>`_ templating
engine. See README for caveats.

0.3.1 (June 1, 2016)
====================

Expand Down
11 changes: 9 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ arbitrary template inheritance, even if a block is defined in the child template
but not in the parent. Generally it works like ``render_to_string`` from Django,
but allows you to specify a block to render.

Features
========

* Render a specific block from a template
* Fully supports the Django templating engine
* Partially supports the `Jinja2 <http://jinja.pocoo.org/>`_ engine: it does
not currently process the ``extends`` tag.

Requirements
============

Django Render Block supports Django 1.8 and 1.9. You must use the Django
template rendering engine (the default) to render specific blocks.
Django Render Block supports Django 1.8 and 1.9.

Examples
========
Expand Down
12 changes: 12 additions & 0 deletions render_block/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

from django.template import loader
from django.template.backends.django import Template as DjangoTemplate
try:
from django.template.backends.jinja2 import Template as Jinja2Template
except ImportError:
# Most likely Jinja2 isn't installed, in that case just create a class since
# we always want it to be false anyway.
class Jinja2Template(object):
pass

from render_block.django import django_render_block
from render_block.exceptions import BlockNotFound, UnsupportedEngine
Expand Down Expand Up @@ -30,6 +37,11 @@ def render_block_to_string(template_name, block_name, context=None):
# The Django backend.
if isinstance(t, DjangoTemplate):
return django_render_block(t, block_name, context)

elif isinstance(t, Jinja2Template):
from render_block.jinja2 import jinja2_render_block
return jinja2_render_block(t, block_name, context)

else:
raise UnsupportedEngine(
'Can only render blocks from the Django template backend.')
17 changes: 17 additions & 0 deletions render_block/jinja2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from render_block.base import BlockNotFound

def jinja2_render_block(template, block_name, context):
# Get the underlying jinja2.environment.Template object.
template = template.template

# Create a new Context instance.
context = template.new_context(context)

# Try to find the wanted block.
try:
gen = template.blocks[block_name](context)
except KeyError:
raise BlockNotFound("block with name '%s' does not exist" % block_name)

# The result from above is a generator which yields unicode strings.
return u''.join([s for s in gen])
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

# Not tested with older versions of Django.
Django==1.8.13
Jinja2==2.8
File renamed without changes.
5 changes: 5 additions & 0 deletions tests/templates/test3_jinja2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% extends 'test1.html' %}

{% block block1 %}{% include "include.html" %}{% endblock %}

{% block block2 %}block2 from test3 - {{ super() }}{% endblock %}
75 changes: 72 additions & 3 deletions tests/tests.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from unittest import skip

from django.template import Context
from django.test import override_settings, TestCase
from django.utils import six

from render_block import render_block_to_string, BlockNotFound, UnsupportedEngine


class TestCases(TestCase):
class TestDjango(TestCase):
"""Test the Django templating engine."""
def assertExceptionMessageEquals(self, exception, expected):
result = exception.message if six.PY2 else exception.args[0]
self.assertEqual(expected, result)
Expand Down Expand Up @@ -38,12 +41,12 @@ def test_no_block(self):

def test_include(self):
"""Ensure that an include tag in a block still works."""
result = render_block_to_string('test3.html', 'block1')
result = render_block_to_string('test3_django.html', 'block1')
self.assertEqual(result, u'included template')

def test_super(self):
"""Test that block.super works."""
result = render_block_to_string('test3.html', 'block2')
result = render_block_to_string('test3_django.html', 'block2')
self.assertEqual(result, u'block2 from test3 - block2 from test1')

def test_subblock(self):
Expand Down Expand Up @@ -76,3 +79,69 @@ def test_different_backend(self):
render_block_to_string('test1.html', 'noblock')
self.assertExceptionMessageEquals(exc.exception,
"Can only render blocks from the Django template backend.")


@override_settings(
TEMPLATES=[{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': ['tests/templates'],
'APP_DIRS': True,
},]
)
class TestJinja2(TestCase):
"""Test the Django templating engine."""
def assertExceptionMessageEquals(self, exception, expected):
result = exception.message if six.PY2 else exception.args[0]
self.assertEqual(expected, result)

def test_block(self):
"""Test rendering an individual block."""
result = render_block_to_string('test1.html', 'block1')
self.assertEqual(result, u'block1 from test1')

# No reason this shouldn't work, but just in case.
result = render_block_to_string('test1.html', 'block2')
self.assertEqual(result, u'block2 from test1')

def test_override(self):
"""This block is overridden in test2."""
result = render_block_to_string('test2.html', 'block1')
self.assertEqual(result, u'block1 from test2')

@skip('Not currently supported.')
def test_inherit(self):
"""This block is inherited from test1."""
result = render_block_to_string('test2.html', 'block2')
self.assertEqual(result, u'block2 from test1')

def test_no_block(self):
"""Check if there's no block available an exception is raised."""
with self.assertRaises(BlockNotFound) as exc:
render_block_to_string('test1.html', 'noblock')
self.assertExceptionMessageEquals(exc.exception,
"block with name 'noblock' does not exist")

def test_include(self):
"""Ensure that an include tag in a block still works."""
result = render_block_to_string('test3_jinja2.html', 'block1')
self.assertEqual(result, u'included template')

@skip('Not currently supported.')
def test_super(self):
"""Test that super() works."""
result = render_block_to_string('test3_jinja2.html', 'block2')
self.assertEqual(result, u'block2 from test3 - block2 from test1')

def test_subblock(self):
"""Test that a block within a block works."""
result = render_block_to_string('test5.html', 'block1')
self.assertEqual(result, u'block3 from test5')

result = render_block_to_string('test5.html', 'block3')
self.assertEqual(result, u'block3 from test5')

def test_context(self):
"""Test that a context is properly rendered in a template."""
data = u'block2 from test5'
result = render_block_to_string('test5.html', 'block2', {'foo': data})
self.assertEqual(result, data)
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH
commands =
python manage.py test
deps =
Jinja2==2.8
django18: Django>=1.8,<1.9
django19: Django>=1.9,<1.10
django110: https://codeload.github.com/django/django/zip/master

0 comments on commit c78a518

Please sign in to comment.