Added support for {{ block.super }}. Dropped support for Django 1.1.X. Fixed #88.
This commit is contained in:
committed by
Jannis Leidel
parent
55ba6a2014
commit
fdc05a64de
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import sys
|
||||
from types import MethodType
|
||||
from fnmatch import fnmatch
|
||||
from optparse import make_option
|
||||
|
||||
@@ -12,6 +13,8 @@ from django.core.management.base import NoArgsCommand, CommandError
|
||||
from django.template import Context, Template, TemplateDoesNotExist, TemplateSyntaxError
|
||||
from django.utils.datastructures import SortedDict
|
||||
from django.utils.importlib import import_module
|
||||
from django.template.loader import get_template
|
||||
from django.template.loader_tags import ExtendsNode, BlockNode, BLOCK_CONTEXT_KEY
|
||||
|
||||
try:
|
||||
from django.template.loaders.cached import Loader as CachedLoader
|
||||
@@ -25,6 +28,14 @@ from compressor.templatetags.compress import CompressorNode
|
||||
from compressor.utils import walk, any
|
||||
|
||||
|
||||
def patched_get_parent(self, context):
|
||||
# Patch template returned by get_parent to make sure their _render method is
|
||||
# just returning the context instead of actually rendering stuff.
|
||||
compiled_template = self._old_get_parent(context)
|
||||
compiled_template._render = MethodType(lambda self, c: c, compiled_template)
|
||||
return compiled_template
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
help = "Compress content outside of the request/response cycle"
|
||||
option_list = NoArgsCommand.option_list + (
|
||||
@@ -149,7 +160,8 @@ class Command(NoArgsCommand):
|
||||
"template %s\n" % template_name)
|
||||
nodes = list(self.walk_nodes(template))
|
||||
if nodes:
|
||||
compressor_nodes.setdefault(template_name, []).extend(nodes)
|
||||
template.template_name = template_name
|
||||
compressor_nodes.setdefault(template, []).extend(nodes)
|
||||
|
||||
if not compressor_nodes:
|
||||
raise OfflineGenerationError(
|
||||
@@ -157,14 +169,30 @@ class Command(NoArgsCommand):
|
||||
|
||||
if verbosity > 0:
|
||||
log.write("Found 'compress' tags in:\n\t" +
|
||||
"\n\t".join(compressor_nodes.keys()) + "\n")
|
||||
"\n\t".join((t.template_name for t in compressor_nodes.keys())) + "\n")
|
||||
|
||||
log.write("Compressing... ")
|
||||
count = 0
|
||||
results = []
|
||||
context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
|
||||
for nodes in compressor_nodes.values():
|
||||
for template, nodes in compressor_nodes.iteritems():
|
||||
context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
|
||||
extra_context = {}
|
||||
firstnode = template.nodelist[0]
|
||||
if isinstance(firstnode, ExtendsNode):
|
||||
# If this template has a ExtendsNode, we apply our patch to
|
||||
# generate the necessary context, and then use it for all the
|
||||
# nodes in it, just in case (we don't know which nodes were
|
||||
# in a block)
|
||||
firstnode._old_get_parent = firstnode.get_parent
|
||||
firstnode.get_parent = MethodType(patched_get_parent, firstnode)
|
||||
extra_context = firstnode.render(context)
|
||||
context.render_context = extra_context.render_context
|
||||
for node in nodes:
|
||||
context.push()
|
||||
if extra_context and node._block_name:
|
||||
context['block'] = context.render_context[BLOCK_CONTEXT_KEY].pop(node._block_name)
|
||||
if context['block']:
|
||||
context['block'].context = context
|
||||
key = get_offline_cachekey(node.nodelist)
|
||||
try:
|
||||
result = node.render(context, forced=True)
|
||||
@@ -172,19 +200,22 @@ class Command(NoArgsCommand):
|
||||
raise CommandError("An error occured during rending: "
|
||||
"%s" % e)
|
||||
cache.set(key, result, settings.COMPRESS_OFFLINE_TIMEOUT)
|
||||
context.pop()
|
||||
results.append(result)
|
||||
count += 1
|
||||
log.write("done\nCompressed %d block(s) from %d template(s).\n" %
|
||||
(count, len(compressor_nodes)))
|
||||
return count, results
|
||||
|
||||
def walk_nodes(self, node):
|
||||
def walk_nodes(self, node, block_name=None):
|
||||
for node in getattr(node, "nodelist", []):
|
||||
if (isinstance(node, CompressorNode) or
|
||||
node.__class__.__name__ == "CompressorNode"): # for 1.1.X
|
||||
if isinstance(node, BlockNode):
|
||||
block_name = node.name
|
||||
if isinstance(node, CompressorNode):
|
||||
node._block_name = block_name
|
||||
yield node
|
||||
else:
|
||||
for node in self.walk_nodes(node):
|
||||
for node in self.walk_nodes(node, block_name=block_name):
|
||||
yield node
|
||||
|
||||
def handle_extensions(self, extensions=('html',)):
|
||||
|
||||
16
compressor/tests/templates/base.html
Normal file
16
compressor/tests/templates/base.html
Normal file
@@ -0,0 +1,16 @@
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
{% block js%}
|
||||
<script type="text/javascript">
|
||||
alert("test 3");
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<style type="text/css">
|
||||
body {
|
||||
background: {{ color|default:"purple" }};
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% load compress %}
|
||||
{% spaceless %}
|
||||
|
||||
{% block content %}{% spaceless %}
|
||||
{% compress css%}
|
||||
<style type="text/css">
|
||||
body {
|
||||
@@ -19,4 +21,22 @@
|
||||
alert("test 2");
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endspaceless %}
|
||||
{% endspaceless %}{% endblock %}
|
||||
|
||||
{% block js %}{% spaceless %}
|
||||
{% compress js %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript">
|
||||
alert("test 4");
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endspaceless %}{% endblock %}
|
||||
|
||||
{% block css %}{% spaceless %}
|
||||
{% compress css %}
|
||||
{{ block.super }}
|
||||
<style type="text/css">
|
||||
body { color: orange ; }
|
||||
</style>
|
||||
{% endcompress %}
|
||||
{% endspaceless %}{% endblock %}
|
||||
|
||||
@@ -466,11 +466,13 @@ class OfflineGenerationTestCase(TestCase):
|
||||
|
||||
def test_offline(self):
|
||||
count, result = CompressCommand().compress()
|
||||
self.assertEqual(3, count)
|
||||
self.assertEqual(5, count)
|
||||
self.assertEqual([
|
||||
css_tag('/media/CACHE/css/cd579b7deb7d.css')+'\n',
|
||||
u'<script type="text/javascript" src="/media/CACHE/js/0a2bb9a287c0.js" charset="utf-8"></script>',
|
||||
u'<script type="text/javascript" src="/media/CACHE/js/fb1736ad48b7.js" charset="utf-8"></script>',
|
||||
u'<script type="text/javascript" src="/media/CACHE/js/770a7311729e.js" charset="utf-8"></script>',
|
||||
u'<link rel="stylesheet" href="/media/CACHE/css/67ed6aff7f7b.css" type="text/css" />\n',
|
||||
], result)
|
||||
# Template rendering should use the cache. FIXME: how to make sure of it ? Should we test the cache
|
||||
# key<->values ourselves?
|
||||
@@ -483,11 +485,13 @@ class OfflineGenerationTestCase(TestCase):
|
||||
'color': 'blue',
|
||||
}
|
||||
count, result = CompressCommand().compress()
|
||||
self.assertEqual(3, count)
|
||||
self.assertEqual(5, count)
|
||||
self.assertEqual([
|
||||
css_tag('/media/CACHE/css/ee62fbfd116a.css')+'\n',
|
||||
u'<script type="text/javascript" src="/media/CACHE/js/0a2bb9a287c0.js" charset="utf-8"></script>',
|
||||
u'<script type="text/javascript" src="/media/CACHE/js/fb1736ad48b7.js" charset="utf-8"></script>',
|
||||
u'<script type="text/javascript" src="/media/CACHE/js/770a7311729e.js" charset="utf-8"></script>',
|
||||
u'<link rel="stylesheet" href="/media/CACHE/css/73e015f740c6.css" type="text/css" />\n',
|
||||
], result)
|
||||
# Template rendering should use the cache. FIXME: how to make sure of it ? Should we test the cache
|
||||
# key<->values ourselves?
|
||||
|
||||
@@ -16,6 +16,10 @@ HEAD
|
||||
To revert to the previous way simply set the ``COMPRESS_CACHE_KEY_FUNCTION``
|
||||
to ``'django_compressor.cache.socket_cachekey'``.
|
||||
|
||||
- Added support for ``{{ block.super }}`` to ``compress`` management command.
|
||||
|
||||
- Dropped Django 1.1.X support.
|
||||
|
||||
- Added Compass filter (beta).
|
||||
|
||||
- Fixed compiler filters on Windows.
|
||||
|
||||
28
tox.ini
28
tox.ini
@@ -13,34 +13,6 @@ commands =
|
||||
make clean
|
||||
make html
|
||||
|
||||
[testenv:py25-1.1.X]
|
||||
basepython = python2.5
|
||||
deps =
|
||||
unittest2
|
||||
BeautifulSoup
|
||||
html5lib
|
||||
coverage
|
||||
django==1.1.4
|
||||
|
||||
[testenv:py26-1.1.X]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
unittest2
|
||||
BeautifulSoup
|
||||
html5lib
|
||||
coverage
|
||||
django==1.1.4
|
||||
|
||||
[testenv:py27-1.1.X]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
unittest2
|
||||
BeautifulSoup
|
||||
html5lib
|
||||
coverage
|
||||
django==1.1.4
|
||||
|
||||
|
||||
[testenv:py25-1.2.X]
|
||||
basepython = python2.5
|
||||
deps =
|
||||
|
||||
Reference in New Issue
Block a user