# Twisted Web's DOM Templates

## Intro

Most templating systems provide commands that you embed in the HTML to repeat elements or include fragments from other files. This works fairly well for simple constructs; however, as soon as the programmer wants to make the logic even slightly more complicated, the templating system must be bent in ways it was never meant to be used.

The theory behind `DOMTemplate` is that Python code, rather than special syntax in the HTML template, should be used to manipulate the structure of the HTML. `DOMTemplate` uses the Document Object Model (DOM), a W3 standard tree-based representation of an HTML document. The DOM provides an API that allows you to traverse nodes in the tree, examine their attributes, move, add, and delete them. For more information on using DOM in Python, see The xml.dom module documentation.

## Before we begin

You'll need to start a plain Twisted Web server.

    mktap web --path ~/public_html
    twistd -f web.tap

For more detailed information on this, see the guide to Installing and Using Twisted.Web.

Once you do this you should be able to throw any files in `~/public_html`, and they'll be served on localhost:8080. Twisted Web also supports a number of special script types; the one we'll be using here is an `.rpy`, or Resource Script.

A Resource Script is simply a python file ending with the extension `.rpy`, which is required to create an instance of a (subclass of a) `twisted.web.resource.Resource`. The `Resource` subclass we'll be using in this example is, of course, `DOMTemplate`.

Make sure the `TwistedQuotes` directory is on your `PYTHONPATH`, put `webquotes.rpy` and `WebQuotes.html` in your `~/public_html` directory, and you are ready to go.

## Getting To It

There are three files involved in this example; `webquoteresource.py`, `WebQuotes.html`, and `webquotes.rpy`. `webquoteresource.py` is a normal python module and contains the class definition which will be used, a `DOMTemplate` subclass. `WebQuotes.html` is placed in the web directory and is looked up at runtime by the `DOMTemplate` machinery. It is converted into a DOM tree which is iterated during page rendering. Finally, `webquotes.rpy` is placed in the web directory; each time the URL is visited, the file is executed; it `import`s `webquoteresource.QuoteResource` and instantiates it. This instance is asked to render the page.

### webquoteresource.py

A `DOMTemplate` subclass must do two things: specify a template, and provide methods to handle specific nodes in the template. The first simply requires either a `template` attribute, which should be a string, or a `templateFile` attribute, which should be a file name, specifying the XHTML template. To accomplish the second, we define methods with the prefix `factory_` in our subclass. When the template is rendered, `DOMTemplate` will look for the `view` attribute on any HTML node. If one is found, the corresponding factory method will be called to handle the node.

    from twisted.web import domtemplate
    from twisted.python import domhelpers #helpers for munging the DOM

    import quoters

    class QuoteResource(domtemplate.DOMTemplate):
        """I am a DOMTemplate that displays a fancy quote page."""

        #The template; this must be valid XML (parsable by Python's DOM implementation)
        templateFile = "WebQuotes.html"

        def __init__(self, filenames):
            domtemplate.DOMTemplate.__init__(self)
            self.quoter = quoters.FortuneQuoter(filenames)

        def factory_getQuote(self, request, node):
            """
            Return a (hopefully amusing) quote.
            """
            domhelpers.clearNode(node)
            node.appendChild(self.d.createTextNode(self.quoter.getQuote()))
            return node

        def factory_getTitle(self, request, node):
            """Quotes Galore!"""
            domhelpers.clearNode(node)
            node.appendChild(self.d.createTextNode("Quotes Galore!"))
            return node

Listing 1: webquoteresource.py: Twisted Quotes Web Resource module - listings/TwistedQuotes/webquoteresource.py

### WebQuotes.html

In our example template, we insert a `view` attribute onto the `<title>` node with the value `'getTitle'`. We also insert a `view` attribute on a `<h1>` node with the value `'getTitle'`; this shows the ability of `DOMTemplate` to reuse functionality while applying formatting defined by the template to the output. We also insert a `view` attribute onto a `<pre>` node with the value `'getQuote'`. This is where the real action will take place.

When the DOM is iterated and nodes with view attributes are found, `DOMTemplate` will look in the instance's namespace for a method with the corresponding name, prefixed by `factory_`.

    <html>
        <head>
            <title view="getTitle">
                Title will go here
            </title>
            <style>
                .quote {color: green;}
            </style>
        </head>

        <body>

            <h1 view="getTitle">
                Title will go here
            </h1>

            <pre class="quote" view="getQuote">
                Quote will go here.
            </pre>

        </body>
    </html>

Listing 2: WebQuotes.html: Twisted Quotes Web Template - listings/TwistedQuotes/WebQuotes.xhtml

### webquote.rpy

Finally, we need an `.rpy` file in the web directory that twisted can find and execute. This is simply a matter of importing our module, instantiating our class, and assigning the instance to a variable named `resource`. Twisted will discover this instance and call `render` on it, causing the `DOMTemplate` to be rendered.

    # -*- Python -*-

    import webquoteresource

    #__file__ is defined to be the name of this file; this is to
    #get the sibling file "quotes.txt" which should be in the same directory
    import os
    quotefile = os.path.join(os.path.split(__file__)[0], "quotes.txt")

    #ResourceScript requires us to define 'resource'. This resource is used to render the page.
    resource = webquoteresource.QuoteResource([quotefile])

Listing 3: webquote.rpy: Twisted Quotes Web Application - listings/TwistedQuotes/webquote.rpy

See it in action!

Last modified: Thu Jun 20 22:51:38 EDT 2002

Go Home