To restate your problem, you want to:
- Take text that you've already got in a string (because you loaded it from a database),
- Take more text that you're going to load into a string (because you know where to load it from),
- Make a parent template out of the second string,
- Make a child template out of the first string,
- Set the parent of the child template (from the first string) to be the parent template (from the second string),
- Evaluate the child template.
- Most importantly, you want to avoid having to have anything like
{% extends ...%}
in the child template, because ... why?
- And finally, you want to do this without hacking the core of Django.
Short answer:
Not possible. Out of the box, Django won't do what you're asking.
Long answer:
The entire concept of template inheritance in Django is implemented through the extends
tag. More accurately, it's implemented through the ExtendsNode class of the django.template.loader_tags module, which is created when the extends
tag is parsed. When you create a Template(), it parses its source string, and creates a list of Nodes (stored in the template's nodelist as you noted earlier). At a later date, you can render the template using whatever context you like, as many times as you like.
Roughly, rendering works by calling render() on each node in the nodelist. If the first node in a template's nodelist is an ExtendsNode (and it must be the first node), then template inheritance magic happens. When the ExtendsNode is created, it is given the template's nodelist, and a parent name (either as a string (parent_name) or expression (parent_name_expr). When the ExtendsNode is rendered, it will use its get_parent() method to call get_template(parent_name), which will invoke the template loader mechanism to load the parent template. Once it has the parent template, the ExtendsNode::render() method will work the magic of template inheritance.
Feel free to check out the code yourself.
In order to avoid using a template loader, you would have to do the following:
- Create a class SpecialExtendsNode(ExtendsNode), overriding the
__init__
method and the get_parent
method.
- After creating a template from the child string, create an instance of your subclass, initialized from the parent template.
- Insert your instance of SpecialExtendsNode into the head of the child template's nodelist.
- Pray that none of this is ever changed by the Django developers.
Just to make things easy for you, here's your class:
class SpecialExtendsNode(ExtendsNode):
def __init__( self, nodelist, parent, name ):
self.myparent = parent
ExtendsNode.__init__( self, nodelist, name, None, None )
def get_parent( self ):
return self.myparent
And the code to use it will look like this:
parent = Template( parent_string )
child = Template( child_string )
hack = SpecialExtendsNode( child.nodelist, parent, "parent name" )
child.nodelist.insert( 0, hack )
output = child.render( context )
Now that I've spent the time and effort to give you a gun, and load it with bullets, I'm going to try to convince you to not to pull the trigger, but instead to do things the way everyone else has recommended.
The code I've written here has no error checking, and was written against Django 1.2. While I haven't tested it, I'm 99% sure that it will work on Django 1.2. I have no idea if it will work on any other version of Django. On the other hand, aside from providing the source, the Django developers haven't documented the internals of their template processor, other than to provide documented interfaces for writing new template tags and filters, and a documented interface for writing template loaders (specifically mentioning the use case of loading a template from a database). That means that there is a reasonable case that someday the Django developers may choose to rewrite or heavily modify the template extension mechanism. If they do this, I will 100% guarantee that this code will break. Why? Because it's a hack. This is what hacking the core of Django looks like. It will work for a day, or a week, or even months at a time, but sooner or later, you (or the programmer that comes after you) will upgrade from Django 1.2 to a later version, and then it will break. And when it breaks, I won't be there to help you, and the Django developers will all ask, why didn't you just write a template loader?
Now tell me, which involves more hacking the core of Django -- writing a template loader, which is documented and supported by the developers, or what I just described?