Further polished embedding system - allowed for context-dependent embed nodes to...
authorStephen Burrows <stephen.r.burrows@gmail.com>
Tue, 30 Nov 2010 15:35:42 +0000 (10:35 -0500)
committerStephen Burrows <stephen.r.burrows@gmail.com>
Tue, 30 Nov 2010 16:10:34 +0000 (11:10 -0500)
README
templatetags/embed.py
templatetags/nodes.py
tests.py

diff --git a/README b/README
index e718287..90d12c0 100644 (file)
--- a/README
+++ b/README
@@ -3,7 +3,21 @@ Philo is a foundation for developing web content management systems.
 Prerequisites:
        * Python 2.5.4+ <http://www.python.org/>
        * Django 1.2+ <http://www.djangoproject.com/>
+       * django-mptt 0.4+ <https://github.com/django-mptt/django-mptt/> 
        * (Optional) django-grappelli 2.0+ <http://code.google.com/p/django-grappelli/>
        * (Optional) recaptcha-django r6 <http://code.google.com/p/recaptcha-django/>
+       * (Optional) south 0.7.2+ <http://south.aeracode.org/>
 
 To contribute, please visit the project website <http://philo.ithinksw.org/>.
+
+====
+Using philo
+====
+After installing philo and mptt on your python path, make sure to complete the following steps:
+
+1. add 'philo.middleware.RequestNodeMiddleware' to settings.MIDDLEWARE_CLASSES.
+2. add 'philo' and 'mptt' to settings.INSTALLED_APPS.
+3. include 'philo.urls' somewhere in your urls.py file.
+4. Optionally add a root node to your current Site.
+
+Philo should be ready to go!
\ No newline at end of file
index ef2eeb2..901e163 100644 (file)
@@ -61,23 +61,25 @@ class EmbedContext(object):
 old_extends_node_init = ExtendsNode.__init__
 
 
-def get_embed_dict(nodelist):
+def get_embed_dict(embed_list, context):
        embeds = {}
-       for n in nodelist.get_nodes_by_type(ConstantEmbedNode):
-               if n.content_type not in embeds:
-                       embeds[n.content_type] = [n]
+       for e in embed_list:
+               ct = e.get_content_type(context)
+               if ct not in embeds:
+                       embeds[ct] = [e]
                else:
-                       embeds[n.content_type].append(n)
+                       embeds[ct].append(e)
        return embeds
 
 
 def extends_node_init(self, nodelist, *args, **kwargs):
-       self.embeds = get_embed_dict(nodelist)
+       self.embed_list = nodelist.get_nodes_by_type(ConstantEmbedNode)
        old_extends_node_init(self, nodelist, *args, **kwargs)
 
 
 def render_extends_node(self, context):
        compiled_parent = self.get_parent(context)
+       embeds = get_embed_dict(self.embed_list, context)
        
        if BLOCK_CONTEXT_KEY not in context.render_context:
                context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()
@@ -90,7 +92,7 @@ def render_extends_node(self, context):
        # Add the block nodes from this node to the block context
        # Do the equivalent for embed nodes
        block_context.add_blocks(self.blocks)
-       embed_context.add_embeds(self.embeds)
+       embed_context.add_embeds(embeds)
        
        # If this block's parent doesn't have an extends node it is the root,
        # and its block nodes also need to be added to the block context.
@@ -100,10 +102,16 @@ def render_extends_node(self, context):
                        if not isinstance(node, ExtendsNode):
                                blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
                                block_context.add_blocks(blocks)
-                               embeds = get_embed_dict(compiled_parent.nodelist)
+                               embeds = get_embed_dict(compiled_parent.nodelist.get_nodes_by_type(ConstantEmbedNode), context)
                                embed_context.add_embeds(embeds)
                        break
-
+       
+       # Explicitly render all direct embed children of this node.
+       if self.embed_list:
+               for node in self.nodelist:
+                       if isinstance(node, ConstantEmbedNode):
+                               node.render(context)
+       
        # Call Template._render explicitly so the parser context stays
        # the same.
        return compiled_parent._render(context)
@@ -152,7 +160,7 @@ class ConstantEmbedNode(template.Node):
                try:
                        return template.loader.get_template(template_name)
                except template.TemplateDoesNotExist:
-                       if not hasattr(self, 'template_name') and settings.TEMPLATE_DEBUG:
+                       if hasattr(self, 'template') and settings.TEMPLATE_DEBUG:
                                # Then it's a constant node.
                                raise
                        return False
@@ -201,6 +209,7 @@ class ConstantEmbedNode(template.Node):
                except (KeyError, IndexError):
                        if settings.TEMPLATE_DEBUG:
                                raise
+                       self.mark_rendered_for(context)
                        return settings.TEMPLATE_STRING_IF_INVALID
                
                context.push()
@@ -225,13 +234,11 @@ class EmbedNode(ConstantEmbedNode):
                        self.object_pk = object_pk
                else:
                        self.object_pk = None
-                       self.instance = None
                
                if template_name is not None:
                        self.template_name = template_name
                else:
                        self.template_name = None
-                       self.template = None
        
        def get_instance(self, context):
                if self.object_pk is None:
index 338ac2d..9721ec4 100644 (file)
@@ -68,7 +68,7 @@ class NodeURLNode(template.Node):
 @register.tag(name='node_url')
 def do_node_url(parser, token):
        """
-       {% node_url [for <node>] [as <var] %}
+       {% node_url [for <node>] [as <var>] %}
        {% node_url with <obj> [for <node>] [as <var>] %}
        {% node_url <view_name> [<arg1> [<arg2> ...] ] [for <node>] [as <var>] %}
        {% node_url <view_name> [<key1>=<value1> [<key2>=<value2> ...] ] [for <node>] [as <var>]%}
index b0f40d5..96ac7b6 100644 (file)
--- a/tests.py
+++ b/tests.py
@@ -39,9 +39,10 @@ class TemplateTestCase(TestCase):
                expected_invalid_str = 'INVALID'
                
                failures = []
-               
+               tests = template_tests.items()
+               tests.sort()
                # Run tests
-               for name, vals in template_tests.items():
+               for name, vals in tests:
                        xx, context, result = vals
                        try:
                                test_template = loader.get_template(name)
@@ -96,6 +97,13 @@ class TemplateTestCase(TestCase):
                        # Blocks and includes
                        'block-include01': ('{% extends "simple01" %}{% embed penfield.blog with "embed03" %}{% block one %}{% include "simple01" %}{% embed penfield.blog 1 %}{% endblock %}', {}, "%sSimple%sSimple%s is a lie!" % (blog.title, blog.title, blog.title)),
                        'block-include02': ('{% extends "simple01" %}{% block one %}{% include "simple04" %}{% embed penfield.blog with "embed03" %}{% include "simple04" %}{% embed penfield.blog 1 %}{% endblock %}', {}, "%sSimple%s%s is a lie!%s is a lie!" % (blog.title, blog.title, blog.title, blog.title)),
+                       
+                       # Tests for more complex situations...
+                       'complex01': ('{% block one %}{% endblock %}complex{% block two %}{% endblock %}', {}, 'complex'),
+                       'complex02': ('{% extends "complex01" %}', {}, 'complex'),
+                       'complex03': ('{% extends "complex02" %}{% embed penfield.blog with "embed01" %}', {}, 'complex'),
+                       'complex04': ('{% extends "complex03" %}{% block one %}{% embed penfield.blog 1 %}{% endblock %}', {}, '%scomplex' % blog.title),
+                       'complex05': ('{% extends "complex03" %}{% block one %}{% include "simple04" %}{% endblock %}', {}, '%scomplex' % blog.title),
                }