Ticket #6516: cleanup.diff
File cleanup.diff, 11.1 KB (added by , 17 years ago) |
---|
-
loader_tags.py
1 from django.template import Template SyntaxError, TemplateDoesNotExist, Variable1 from django.template import Template, TemplateSyntaxError, TemplateDoesNotExist, Variable 2 2 from django.template import Library, Node 3 from django.template.loader import get_template , get_template_from_string, find_template_source3 from django.template.loader import get_template 4 4 from django.conf import settings 5 5 from django.utils.safestring import mark_safe 6 6 … … 10 10 pass 11 11 12 12 class BlockNode(Node): 13 def __init__(self, name, nodelist, parent=None): 14 self.name, self.nodelist, self.parent = name, nodelist, parent 13 def __init__(self, name, nodelist): 14 self.name = name 15 self.nodelist = nodelist 16 self.parent = None 15 17 16 18 def __repr__(self): 17 19 return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist) … … 30 32 return mark_safe(self.parent.render(self.context)) 31 33 return '' 32 34 33 def add_parent(self, nodelist): 34 if self.parent: 35 self.parent.add_parent(nodelist) 36 else: 37 self.parent = BlockNode(self.name, nodelist) 35 def insert_as_child(self, parent): 36 eldest = self 37 while eldest.parent: 38 eldest = eldest.parent 39 eldest.parent = BlockNode(parent.name, parent.nodelist) 40 parent.nodelist = self.nodelist 41 parent.parent = self.parent 38 42 39 43 class ExtendsNode(Node): 40 def __init__(self, nodelist, parent_name, parent_name_expr, template_dirs=None):44 def __init__(self, nodelist, extended_name=None, extended_name_expr=None): 41 45 self.nodelist = nodelist 42 self. parent_name, self.parent_name_expr = parent_name, parent_name_expr43 self. template_dirs = template_dirs46 self.extended_name = extended_name 47 self.extended_name_expr = extended_name_expr 44 48 45 def get_parent(self, context):46 if self.parent_name_expr:47 self.parent_name = self.parent_name_expr.resolve(context)48 parent = self.parent_name49 if not parent:50 error_msg = "Invalid template name in 'extends' tag: %r." % parent51 if self.parent_name_expr:52 error_msg += " Got this from the %r variable." % self.parent_name_expr #TODO nice repr.53 raise TemplateSyntaxError, error_msg54 if hasattr(parent, 'render'):55 return parent # parent is a Template object49 def _get_extended_template(self, context): 50 extended_name = self.extended_name 51 if self.extended_name_expr: 52 resolved_expr = self.extended_name_expr.resolve(context) 53 if not resolved_expr: 54 raise TemplateSyntaxError("Can't resolve 'extends' tag argument '%r'" % self.extended_name_expr) 55 # If the expr resolves to a template, just return it. 56 if isinstance(resolved_expr, Template): 57 return resolved_expr 58 # Assume that resolved_expr is the extended templates name string. 59 extended_name = resolved_expr 56 60 try: 57 source, origin = find_template_source(parent, self.template_dirs) 61 return get_template(extended_name) 62 # Translate does not exist errors to syntax errors for extends tag. 58 63 except TemplateDoesNotExist: 59 raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent 60 else: 61 return get_template_from_string(source, origin, parent) 64 raise TemplateSyntaxError("Can't find %r in 'extends' tag" % extended_name) 62 65 63 66 def render(self, context): 64 compiled_parent = self.get_parent(context) 65 parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode) 66 parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)]) 67 for block_node in self.nodelist.get_nodes_by_type(BlockNode): 68 # Check for a BlockNode with this node's name, and replace it if found. 67 extended = self._get_extended_template(context) 68 extended_extends = isinstance(extended.nodelist[0], ExtendsNode) 69 extended_blocks = dict([(n.name, n) for n in extended.nodelist.get_nodes_by_type(BlockNode)]) 70 71 # For each block node in this template. 72 for block in self.nodelist.get_nodes_by_type(BlockNode): 73 # Check extended template for a BlockNode with this block's name 74 # and replace it with this block node if found. 69 75 try: 70 parent_block = parent_blocks[block_node.name] 76 extended_block = extended_blocks[block.name] 77 # If this BlockNode wasn't found in the extended template. 71 78 except KeyError: 72 # This BlockNode wasn't found in the parent template, but the 73 # parent block might be defined in the parent's *parent*, so we 74 # add this BlockNode to the parent's ExtendsNode nodelist, so 75 # it'll be checked when the parent node's render() is called. 76 if parent_is_child: 77 compiled_parent.nodelist[0].nodelist.append(block_node) 79 # If the extended template doesn't extend another, 80 # this block will not be rendered, so we can just drop it. 81 # 82 # If the extended template extends another, 83 # it might be defined higher up the hierarchy. 84 # 85 # For this case, we add this block 86 # to the extended templates ExtendsNode nodelist so it will 87 # be checked when the extended template is rendered. 88 if extended_extends: 89 extended.nodelist[0].nodelist.append(block) 90 # Block was found in extended template 78 91 else: 79 # Keep any existing parents and add a new one. Used by BlockNode. 80 parent_block.parent = block_node.parent 81 parent_block.add_parent(parent_block.nodelist) 82 parent_block.nodelist = block_node.nodelist 83 return compiled_parent.render(context) 92 # Make the extended block a parent of block, 93 # and replace the extended block with block 94 # in the template 95 block.insert_as_child(extended_block) 96 # Return the result of rendering the extended template 97 # now that blocks in the extended template have been replaced with 98 # blocks from this template. 99 return extended.render(context) 84 100 85 101 class ConstantIncludeNode(Node): 86 102 def __init__(self, template_path): … … 95 111 def render(self, context): 96 112 if self.template: 97 113 return self.template.render(context) 98 else: 99 return '' 114 return '' 100 115 101 116 class IncludeNode(Node): 102 117 def __init__(self, template_name): … … 107 122 template_name = self.template_name.resolve(context) 108 123 t = get_template(template_name) 109 124 return t.render(context) 110 except TemplateSyntaxError, e: 125 # If debugging templates, propagate any syntax errors, 126 # otherwise, just eat any any syntax errors. 127 except TemplateSyntaxError: 111 128 if settings.TEMPLATE_DEBUG: 112 129 raise 113 return ''130 # Eat any other errors that may have occurred. 114 131 except: 115 return '' # Fail silently for invalid included templates. 132 pass 133 return '' 116 134 117 135 def do_block(parser, token): 118 136 """ … … 120 138 """ 121 139 bits = token.contents.split() 122 140 if len(bits) != 2: 123 raise TemplateSyntaxError , "'%s' tag takes only one argument" % bits[0]141 raise TemplateSyntaxError("'%s' tag takes only one argument" % bits[0]) 124 142 block_name = bits[1] 125 # Keep track of the names of BlockNodes found in this template, so we can126 # check for duplication.143 # Keep track of the BlockNodes found in this template, 144 # so we can prevent duplication and reuse them. 127 145 try: 128 146 if block_name in parser.__loaded_blocks: 129 raise TemplateSyntaxError , "'%s' tag with name '%s' appears more than once" % (bits[0], block_name)130 parser.__loaded_blocks.append(block_name)131 except AttributeError: # parser.__loaded_blocks isn't a list yet132 parser.__loaded_blocks = [block_name]147 raise TemplateSyntaxError("'%s' tag with name '%s' appears more than once" % (bits[0], block_name)) 148 except AttributeError: 149 # this is the first block, make __loaded_blocks dict 150 parser.__loaded_blocks = {} 133 151 nodelist = parser.parse(('endblock', 'endblock %s' % block_name)) 134 152 parser.delete_first_token() 135 return BlockNode(block_name, nodelist) 153 block_node = BlockNode(block_name, nodelist) 154 parser.__loaded_blocks[block_name] = block_node 155 return block_node 136 156 137 157 def do_extends(parser, token): 138 158 """ … … 142 162 uses the literal value "base" as the name of the parent template to extend, 143 163 or ``{% extends variable %}`` uses the value of ``variable`` as either the 144 164 name of the parent template to extend (if it evaluates to a string) or as 145 the parent tempate it elf (if it evaluates to a Template object).165 the parent tempate itself (if it evaluates to a Template object). 146 166 """ 167 nodelist = parser.parse() 168 # Make reasonably sure that there are no other extends tags. 169 if nodelist.get_nodes_by_type(ExtendsNode): 170 raise TemplateSyntaxError("'%s' tag cannot appear more than once in the same template" % bits[0]) 171 147 172 bits = token.contents.split() 148 173 if len(bits) != 2: 149 raise TemplateSyntaxError, "'%s' takes one argument" % bits[0] 150 parent_name, parent_name_expr = None, None 174 raise TemplateSyntaxError("'%s' takes one argument" % bits[0]) 151 175 if bits[1][0] in ('"', "'") and bits[1][-1] == bits[1][0]: 152 parent_name = bits[1][1:-1]176 return ExtendsNode(nodelist, extended_name=bits[1][1:-1]) 153 177 else: 154 parent_name_expr = parser.compile_filter(bits[1]) 155 nodelist = parser.parse() 156 if nodelist.get_nodes_by_type(ExtendsNode): 157 raise TemplateSyntaxError, "'%s' cannot appear more than once in the same template" % bits[0] 158 return ExtendsNode(nodelist, parent_name, parent_name_expr) 178 return ExtendsNode(nodelist, extended_name_expr=parser.compile_filter(bits[1])) 159 179 160 180 def do_include(parser, token): 161 181 """ 162 Load s a template and rendersit with the current context.182 Load a template and render it with the current context. 163 183 164 184 Example:: 165 185 … … 167 187 """ 168 188 bits = token.contents.split() 169 189 if len(bits) != 2: 170 raise TemplateSyntaxError , "%r tag takes one argument: the name of the template to be included" % bits[0]190 raise TemplateSyntaxError("%r tag takes one argument: the name of the template to be included" % bits[0]) 171 191 path = bits[1] 172 192 if path[0] in ('"', "'") and path[-1] == path[0]: 173 193 return ConstantIncludeNode(path[1:-1])