Changes between Version 59 and Version 60 of GenshiTutorial
- Timestamp:
- Sep 1, 2007, 12:06:24 AM (17 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
GenshiTutorial
v59 v60 9 9 In 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. 10 10 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'''11 The 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''' 12 12 13 13 We'll keep the project as simple as possible, while still showing many of Genshi features and how to best use them: 14 14 * For persistence, we'll use native Python object serialization (via the `pickle` module), instead of an SQL database and an ORM. 15 15 * 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. 16 17 17 18 [[PageOutline(2-3, Content, inline)]] … … 124 125 }}} 125 126 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.127 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'll pass into the template from the controller. 127 128 128 129 There are couple of important things to point out here: … … 131 132 * 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: 132 133 * [http://www.w3schools.com/xhtml/xhtml_html.asp Differences Between XHTML And HTML] at W3Schools 133 * [http://www.sitepoint.com/article/xhtml-introduction /2XHTML - An Introduction] at !SitePoint134 * [http://www.sitepoint.com/article/xhtml-introduction XHTML - An Introduction] at !SitePoint 134 135 * [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, becausedespite 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). 136 137 137 138 We 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: … … 171 172 <h1>Geddit</h1> 172 173 </div> 173 174 174 <p>Welcome!</p> 175 176 175 <div id="footer"> 177 <hr />176 <hr> 178 177 <p class="legalese">© 2007 Edgewall Software</p> 179 178 </div> … … 182 181 }}} 183 182 183 Note 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. 184 184 185 185 === The Data Model === … … 337 337 This template demontrates some aspects of Genshi that we've not seen so far: 338 338 * 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 contentwill 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 complexexpressions 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 tothis: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 343 When you reload the page in the browser, you should get something like this: 344 344 345 345 [[Image(tutorial01.png)]]