In the previous section we saw how Albatross tags can be used to remove presentation logic from your application. In this section we will see how with a simple program we can serve up a tree of template files.
If you look at the output of the simple4/simple.py program you will notice the following lines:
REQUEST_URI /cgi-bin/alsamp/simple4/simple.py SCRIPT_FILENAME /usr/lib/cgi-bin/alsamp/simple4/simple.py SCRIPT_NAME /cgi-bin/alsamp/simple4/simple.py
Now watch what happens when you start appending extra path elements to the end of the URL. Try requesting the following with your browser: http://www.object-craft.com.au/cgi-bin/alsamp/simple4/simple.py/main.html.
You should see the following three lines:
REQUEST_URI /cgi-bin/alsamp/simple4/simple.py/main.html SCRIPT_FILENAME /usr/lib/cgi-bin/alsamp/simple4/simple.py SCRIPT_NAME /cgi-bin/alsamp/simple4/simple.py
The interesting thing is that Apache is still using the simple4/simple.py program to process the browser request. We can use the value of the REQUEST_URI environment variable to locate a template file which will be displayed.
The sample application in the samples/templates/content1 directory demonstrates serving dynamic content based upon the requested URI. The program can be installed in your web server cgi-bin directory by running the following commands.
cd samples/templates/content1 python install.py
The CGI program content.py is shown below.
#!/usr/bin/python import os from albatross import SimpleContext, TemplateLoadError script_name = os.environ['SCRIPT_NAME'] request_uri = os.environ['REQUEST_URI'] page = request_uri[len(script_name) + 1:] if not page or os.path.dirname(page): page = 'main.html' ctx = SimpleContext('templ') ctx.locals.page = page try: templ = ctx.load_template(page) except TemplateLoadError: templ = ctx.load_template('oops.html') templ.to_html(ctx) print 'Content-Type: text/html' print ctx.flush_content()
To demonstrate this application we have three template files; main.html, oops.html, and other.html.
First main.html.
<html> <head> <title>Simple Content Management - main page.</title> </head> <body> <h1>Simple Content Management - main page</h1> <hr noshade> This is the main page. </body> </html>
Now other.html.
<html> <head> <title>Simple Content Management - other page.</title> </head> <body> <h1>Simple Content Management - other page</h1> <hr noshade> This is the other page. </body> </html>
And finally the page for displaying errors; oops.html.
<html> <head> <title>Simple Content Management - error page.</title> </head> <body> <h1>Simple Content Management - error page</h1> <hr noshade> <al-if expr="page == 'oops.html'"> You actually requested the error page! <al-else> Sorry, the page <font color="red"><al-value expr="page"></font> does not exist. </al-if> </body> </html>
Test the program by trying a few requests with your browser:
http://www.object-craft.com.au/cgi-bin/alsamp/content1/content.py
http://www.object-craft.com.au/cgi-bin/alsamp/content1/content.py/main.html
http://www.object-craft.com.au/cgi-bin/alsamp/content1/content.py/other.html
http://www.object-craft.com.au/cgi-bin/alsamp/content1/content.py/error.html
http://www.object-craft.com.au/cgi-bin/alsamp/content1/content.py/oops.html
Let's analyse the program step-by-step. The preamble imports the modules we are going to use.
#!/usr/bin/python import os from albatross import SimpleContext, TemplateLoadError
The next part of the program removes the prefix in the
SCRIPT_NAME variable from the value in the
REQUEST_URI variable. When removing the script name we add
one to the length to ensure that the "/" path separator
between the script and page is also removed. This is important
because the execution context load_template() method uses
os.path.join()
to construct a script filename by combining the
base_dir specified in the constructor and the name passed to the
load_template() method. If any of the path components being
joined begin with a "/" then os.path.join()
creates an
absolute path beginning at the "/".
If no page was specified in the browser request then we use the default page main.html.
script_name = os.environ['SCRIPT_NAME'] request_uri = os.environ['REQUEST_URI'] page = request_uri[len(script_name) + 1:] if not page: page = 'main.html'
The next section of code creates the Albatross execution context and
places the requested filename into the page
local attribute.
It then attempts to load the requested file. If the template file
does not exist the load_template() will raise a
TemplateLoadError
exception. We handle this by loading the
error page oops.html.
The error page displays a message which explains that the requested
page (saved in the page
variable) does not exist.
ctx = SimpleContext('templ') ctx.locals.page = page try: templ = ctx.load_template(page) except TemplateLoadError: templ = ctx.load_template('oops.html')
Looking at the error page oops.html, you will see a new Albatross tag <al-if>.
<al-if expr="page == 'oops.html'"> You actually requested the error page! <al-else> Sorry, the page <font color="red"><al-value expr="page"></font> does not exist. </al-if>
The <al-if> tag allows you to conditionally include or
exclude template content by testing the result of an expression.
Remember that we placed the name of the requested page into the
page
variable, so we are able to display different content when
the browser actually requests oops.html.
Finally, the remainder of the program displays the selected HTML page.
templ.to_html(ctx) print 'Content-Type: text/html' print ctx.flush_content()