Monday, May 4, 2009

Django Templates and NodeLists

Whether dealing with a complex web application or a simple web site with relatively few pages, using templates is generally a good idea. With complex page structures, this is unavoidable. The alternative would be to implement the page structure manually. Even with simplistic web pages, there is often a dynamic element that is undesirable to manually edit. If the web application is built with a Python web application, developers have several template engines to choose from. TuboGears, for instance, offers support for several third-party template engines. Django, on the other hand, offers their own template rendering system. The Django template engine provides many of the same features as do other Python template engines. The syntax used in Django templates is simplistic and easy to use. Inside the template engine are two closely related classes that represent key template concepts and are illustrated below. These classes are Template and NodeList.



The Template class represents a template in its' entirety. During the construction of Template instances, the template is compiled. Since this process takes place in the Template constructor, the template string is a required constructor parameter. Since any given Template instance is compiled, it may be rendered at any time. The template passed to the constructor is only compiled once since the compilation takes place in the constructor. Template instances support iteration. Each iteration through a particular Template instance yields a node from the NodeList instance that resulted from compiling the template. Invoking Template.render() will in turn invoke NodeList.render(), passing along the specified context.

The NodeList represents a collection of nodes that result from compiling a template string. The majority of these nodes are HTML elements, template variables, or some Python language construct such as an if statement. NodeList instances are also instances of the Python list primitive. This means that each node contained within the list behaves just like a Python list element. The NodeList.render() method will cumulatively invoke render() on each node contained within the list. The end result is the rendered template. This rendering behavior provided by the NodeList.render() method can be considered polymorphic. The method iteratively invokes render() on anonymous instances. All it cares about is the render() interface.