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 os
|
||||||
import sys
|
import sys
|
||||||
|
from types import MethodType
|
||||||
from fnmatch import fnmatch
|
from fnmatch import fnmatch
|
||||||
from optparse import make_option
|
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.template import Context, Template, TemplateDoesNotExist, TemplateSyntaxError
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.importlib import import_module
|
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:
|
try:
|
||||||
from django.template.loaders.cached import Loader as CachedLoader
|
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
|
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):
|
class Command(NoArgsCommand):
|
||||||
help = "Compress content outside of the request/response cycle"
|
help = "Compress content outside of the request/response cycle"
|
||||||
option_list = NoArgsCommand.option_list + (
|
option_list = NoArgsCommand.option_list + (
|
||||||
@@ -149,7 +160,8 @@ class Command(NoArgsCommand):
|
|||||||
"template %s\n" % template_name)
|
"template %s\n" % template_name)
|
||||||
nodes = list(self.walk_nodes(template))
|
nodes = list(self.walk_nodes(template))
|
||||||
if nodes:
|
if nodes:
|
||||||
compressor_nodes.setdefault(template_name, []).extend(nodes)
|
template.template_name = template_name
|
||||||
|
compressor_nodes.setdefault(template, []).extend(nodes)
|
||||||
|
|
||||||
if not compressor_nodes:
|
if not compressor_nodes:
|
||||||
raise OfflineGenerationError(
|
raise OfflineGenerationError(
|
||||||
@@ -157,14 +169,30 @@ class Command(NoArgsCommand):
|
|||||||
|
|
||||||
if verbosity > 0:
|
if verbosity > 0:
|
||||||
log.write("Found 'compress' tags in:\n\t" +
|
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... ")
|
log.write("Compressing... ")
|
||||||
count = 0
|
count = 0
|
||||||
results = []
|
results = []
|
||||||
|
for template, nodes in compressor_nodes.iteritems():
|
||||||
context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
|
context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
|
||||||
for nodes in compressor_nodes.values():
|
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:
|
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)
|
key = get_offline_cachekey(node.nodelist)
|
||||||
try:
|
try:
|
||||||
result = node.render(context, forced=True)
|
result = node.render(context, forced=True)
|
||||||
@@ -172,19 +200,22 @@ class Command(NoArgsCommand):
|
|||||||
raise CommandError("An error occured during rending: "
|
raise CommandError("An error occured during rending: "
|
||||||
"%s" % e)
|
"%s" % e)
|
||||||
cache.set(key, result, settings.COMPRESS_OFFLINE_TIMEOUT)
|
cache.set(key, result, settings.COMPRESS_OFFLINE_TIMEOUT)
|
||||||
|
context.pop()
|
||||||
results.append(result)
|
results.append(result)
|
||||||
count += 1
|
count += 1
|
||||||
log.write("done\nCompressed %d block(s) from %d template(s).\n" %
|
log.write("done\nCompressed %d block(s) from %d template(s).\n" %
|
||||||
(count, len(compressor_nodes)))
|
(count, len(compressor_nodes)))
|
||||||
return count, results
|
return count, results
|
||||||
|
|
||||||
def walk_nodes(self, node):
|
def walk_nodes(self, node, block_name=None):
|
||||||
for node in getattr(node, "nodelist", []):
|
for node in getattr(node, "nodelist", []):
|
||||||
if (isinstance(node, CompressorNode) or
|
if isinstance(node, BlockNode):
|
||||||
node.__class__.__name__ == "CompressorNode"): # for 1.1.X
|
block_name = node.name
|
||||||
|
if isinstance(node, CompressorNode):
|
||||||
|
node._block_name = block_name
|
||||||
yield node
|
yield node
|
||||||
else:
|
else:
|
||||||
for node in self.walk_nodes(node):
|
for node in self.walk_nodes(node, block_name=block_name):
|
||||||
yield node
|
yield node
|
||||||
|
|
||||||
def handle_extensions(self, extensions=('html',)):
|
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 %}
|
{% load compress %}
|
||||||
{% spaceless %}
|
|
||||||
|
{% block content %}{% spaceless %}
|
||||||
{% compress css%}
|
{% compress css%}
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
body {
|
body {
|
||||||
@@ -19,4 +21,22 @@
|
|||||||
alert("test 2");
|
alert("test 2");
|
||||||
</script>
|
</script>
|
||||||
{% endcompress %}
|
{% 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):
|
def test_offline(self):
|
||||||
count, result = CompressCommand().compress()
|
count, result = CompressCommand().compress()
|
||||||
self.assertEqual(3, count)
|
self.assertEqual(5, count)
|
||||||
self.assertEqual([
|
self.assertEqual([
|
||||||
css_tag('/media/CACHE/css/cd579b7deb7d.css')+'\n',
|
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/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/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)
|
], result)
|
||||||
# Template rendering should use the cache. FIXME: how to make sure of it ? Should we test the cache
|
# Template rendering should use the cache. FIXME: how to make sure of it ? Should we test the cache
|
||||||
# key<->values ourselves?
|
# key<->values ourselves?
|
||||||
@@ -483,11 +485,13 @@ class OfflineGenerationTestCase(TestCase):
|
|||||||
'color': 'blue',
|
'color': 'blue',
|
||||||
}
|
}
|
||||||
count, result = CompressCommand().compress()
|
count, result = CompressCommand().compress()
|
||||||
self.assertEqual(3, count)
|
self.assertEqual(5, count)
|
||||||
self.assertEqual([
|
self.assertEqual([
|
||||||
css_tag('/media/CACHE/css/ee62fbfd116a.css')+'\n',
|
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/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/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)
|
], result)
|
||||||
# Template rendering should use the cache. FIXME: how to make sure of it ? Should we test the cache
|
# Template rendering should use the cache. FIXME: how to make sure of it ? Should we test the cache
|
||||||
# key<->values ourselves?
|
# key<->values ourselves?
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ HEAD
|
|||||||
To revert to the previous way simply set the ``COMPRESS_CACHE_KEY_FUNCTION``
|
To revert to the previous way simply set the ``COMPRESS_CACHE_KEY_FUNCTION``
|
||||||
to ``'django_compressor.cache.socket_cachekey'``.
|
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).
|
- Added Compass filter (beta).
|
||||||
|
|
||||||
- Fixed compiler filters on Windows.
|
- Fixed compiler filters on Windows.
|
||||||
|
|||||||
28
tox.ini
28
tox.ini
@@ -13,34 +13,6 @@ commands =
|
|||||||
make clean
|
make clean
|
||||||
make html
|
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]
|
[testenv:py25-1.2.X]
|
||||||
basepython = python2.5
|
basepython = python2.5
|
||||||
deps =
|
deps =
|
||||||
|
|||||||
Reference in New Issue
Block a user