Edgewall Software

Changes between Version 59 and Version 60 of GenshiTutorial


Ignore:
Timestamp:
Sep 1, 2007, 12:06:24 AM (17 years ago)
Author:
cmlenz
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • GenshiTutorial

    v59 v60  
    99In this tutorial we'll create a simple Python web application based on [http://cherrpy.org/ CherryPy 3]. !CherryPy was chosen because it provides a convenient level of abstraction over raw CGI or [http://wsgi.org/wsgi WSGI] development, but is less ambitious than full-stack web frameworks such as [http://pylonshq.com/ Pylons] or [http://www.djangoproject.com/ Django], which tend to come with a preferred templating language, and often show significant bias towards that language.
    1010
    11 The application is a stripped-down version of sites such as [http://reddit.com/ reddit] or [http://digg.com/ digg]: it lets users submit links to online articles they find interesting, and then lets other users comment on those stories. Just for kicks, we'll call that application '''Geddit'''
     11The application we'll build here is a stripped-down version of sites such as [http://reddit.com/ reddit] or [http://digg.com/ digg]: it lets users submit links to online articles they find interesting, and then lets other users comment on those stories. Just for kicks, we'll call that application '''Geddit'''
    1212
    1313We'll keep the project as simple as possible, while still showing many of Genshi features and how to best use them:
    1414 * For persistence, we'll use native Python object serialization (via the `pickle` module), instead of an SQL database and an ORM.
    1515 * There's no authentication of any kind. Anyone can submit links, anyone can comment.
     16 * We'll start with the basics (rendering templates, handling forms, etc), and then continue by adding features such as Atom feeds and an AJAX interface.
    1617
    1718[[PageOutline(2-3, Content, inline)]]
     
    124125}}}
    125126
    126 This is basically an almost static XHTML file with some simple variable substitution: the string `$title` will be replaced by a variable of that name that we pass into the template from the controller.
     127This is basically an almost static XHTML file with some simple variable substitution: the string `$title` will be replaced by a variable of that name that we'll pass into the template from the controller.
    127128
    128129There are couple of important things to point out here:
     
    131132 * The template will be parsed by Genshi using an XML parser, which means that '''it needs to be well-formed XML'''. If you know HTML but are unfamiliar with XML/XHTML, you will need to read up on the topic. Here are a couple of good references:
    132133   * [http://www.w3schools.com/xhtml/xhtml_html.asp Differences Between XHTML And HTML] at W3Schools
    133    * [http://www.sitepoint.com/article/xhtml-introduction/2 XHTML - An Introduction] at !SitePoint
     134   * [http://www.sitepoint.com/article/xhtml-introduction XHTML - An Introduction] at !SitePoint
    134135   * [http://www.webmonkey.com/00/50/index2a.html XHTML Overview] at Webmonkey
    135  * That the template uses XHTML does not mean that your web-application will generate XHTML! You can choose whether you'd rather just generate good old HTML 4.01, because despite all the hype, that's still the format that works best in most browsers (see [http://webkit.org/blog/?p=68 this blog post] over at Surfin' Safari for some background).
     136 * Just because the template uses XHTML does not mean that our web-application should generate XHTML! While that is possible, you can also choose to generate good old HTML 4.01, because, despite all the hype, that's still the format that works best in most browsers (see [http://webkit.org/blog/?p=68 this blog post] over at Surfin' Safari for some background).
    136137
    137138We now need to change the controller code so that this template is used. First, add the Genshi `TemplateLoader` to the imports at the top of the `geddit/controller.py` file, and instantiate a loader for the `geddit/templates` directory:
     
    171172      <h1>Geddit</h1>
    172173    </div>
    173 
    174174    <p>Welcome!</p>
    175 
    176175    <div id="footer">
    177       <hr />
     176      <hr>
    178177      <p class="legalese">© 2007 Edgewall Software</p>
    179178    </div>
     
    182181}}}
    183182
     183Note that the output has some subtle differences compared to the template, even beyond the variable substitution that has taken place: Genshi has added a proper HTML `DOCTYPE` (important to get the browser to render using standards mode, through a commonly employed mechanism in web browsers called “[http://www.ericmeyeroncss.com/bonus/render-mode.html doctype switching]”.) It has also removed the XHTML namespace declaration, because we're rendering to HTML, and HTML doesn't support XML namespaces. And the `<hr>` element in the footer is missing the trailing slash that can be used in XML markup for empty elements; HTML user agents know that `<hr>` is always an empty element, and including either the trailing slash, or even adding an explicit `</hr>` end tag would be invalid pr potentially confuse some browsers.
    184184
    185185=== The Data Model ===
     
    337337This template demontrates some aspects of Genshi that we've not seen so far:
    338338 * We declare the `py:` namespace prefix on the `<html>` element, which is required to be able to add [wiki:Documentation/xml-templates.html#template-directives directives] to the template.
    339  * There's a `py:if` [wiki:Documentation/xml-templates.html#conditional-sections condition] on the `<ol>` element. That means that the `<ol>` and all nested content will only be included in the output stream if the expression `links` evaluates to a truth value. In this case we know that `links` is a list (assembled by the `Root.index()` method), so if the list is empty, the `<ol>` will be skipped.
    340  * Next up, we've attached a `py:for` [wiki:Documentation/xml-templates.html#looping loop] to the `<li>` element. `py:for="link in reversed(links)"`. What this does is that the `<li>` element will be repeated for every item in the `links` list. The `link` variable is bound to the current item in the list on every step.
    341  * You can tell that we can also use more complex expressions than just simple variable substitutions: the directives such as `py:if` and `py:for` take Python expressions of any complexity, while you can include complex expressions in other places by putting them inside curly braces prefixed with a dollar sign (`${...}`).
    342 
    343 When you reload the page in the browser, you should see a page similar to this:
     339 * There's a `py:if` [wiki:Documentation/xml-templates.html#conditional-sections condition] on the `<ol>` element. That means that the `<ol>` and everything it contains will only be included in the output stream if the expression `links` evaluates to a truth value. In this case we know that `links` is a list (assembled by the `Root.index()` method), so if the list is empty, the `<ol>` will be skipped.
     340 * Next up, we've attached a `py:for` [wiki:Documentation/xml-templates.html#looping loop] to the `<li>` element. What this does is that the `<li>` element will be repeated for every item in the `links` list. The `link` variable is bound to the current item in the list on every step.
     341 * You can tell that we can also use more complex expressions than just simple variable substitutions: the directives such as `py:if` and `py:for` take Python expressions of any complexity, and you can include Python expressions in other places by putting them inside curly braces prefixed with a dollar sign (`${...}`).
     342
     343When you reload the page in the browser, you should get something like this:
    344344
    345345[[Image(tutorial01.png)]]