Changes between Version 32 and Version 33 of GenshiTutorial
- Timestamp:
- Aug 30, 2007, 3:20:18 PM (17 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
GenshiTutorial
v32 v33 187 187 188 188 189 class Submission(object):189 class Link(object): 190 190 191 191 def __init__(self, username, url, title): … … 194 194 self.title = title 195 195 self.time = datetime.utcnow() 196 self. code= hex(hash(tuple([username, url, title, self.time])))[2:]196 self.id = hex(hash(tuple([username, url, title, self.time])))[2:] 197 197 self.comments = [] 198 198 … … 219 219 {{{ 220 220 #!python 221 from geddit.model import Submission, Comment221 from geddit.model import Link, Comment 222 222 }}} 223 223 … … 257 257 #!pycon 258 258 >>> from geddit.model import * 259 >>> submission1 = Submission(username='joe', url='http://example.org/', title='An example') 260 >>> submission1.add_comment(username='jack', content='Bla bla bla') 261 >>> submission1.add_comment(username='joe', content='Bla bla bla, bla bla.') 262 >>> submission2 = Submission(username='annie', url='http://reddit.com/', title='The real thing') 263 259 >>> link1 = Link(username='joe', url='http://example.org/', title='An example') 260 >>> link1.add_comment(username='jack', content='Bla bla bla') 261 >>> link1.add_comment(username='joe', content='Bla bla bla, bla bla.') 262 >>> link2 = Link(username='annie', url='http://reddit.com/', title='The real thing') 264 263 >>> import pickle 265 >>> pickle.dump({ 266 ... submission1.code: submission1, submission2.code: submission2 267 ... }, open('geddit.db', 'wb')) 268 }}} 269 270 You should now have two submissions in the pickle file, with the first submission having a comment, as well as a reply to that comment. Restart the CherryPy server by running: 264 >>> pickle.dump({link1.id: link1, link2.id: link2}, open('geddit.db', 'wb')) 265 }}} 266 267 You should now have two links in the pickle file, with the first link having a comment, as well as a reply to that comment. Restart the CherryPy server by running: 271 268 272 269 {{{ … … 276 273 == Extending the Template == 277 274 278 Now let's change the `Root.index()` method in `geddit/controller.py` to pass the submissions list to the template:275 Now let's change the `Root.index()` method in `geddit/controller.py` to pass the links list to the template: 279 276 280 277 {{{ … … 282 279 @cherrypy.expose 283 280 def index(self): 284 submissions = sorted(self.data.values(), 285 key=operator.attrgetter('time')) 281 links = sorted(self.data.values(), key=operator.attrgetter('time')) 286 282 287 283 tmpl = loader.load('index.html') 288 stream = tmpl.generate( submissions=submissions)284 stream = tmpl.generate(links=links) 289 285 return stream.render('html', doctype='html') 290 286 }}} 291 287 292 And finally, we'll modify the `index.html` template so that it displays the submissions in a simple ordered list. While we're at it, let's add a link to submit new items:288 And finally, we'll modify the `index.html` template so that it displays the links in a simple ordered list. While we're at it, let's add a link to submit new items: 293 289 294 290 {{{ … … 306 302 <p><a href="/submit/">Submit new link</a></p> 307 303 308 <ol py:if=" submissions">309 <li py:for=" submission in reversed(submissions)">310 <a href="${ submission.url}">${submission.title}</a>311 posted by ${ submission.username}312 at ${ submission.time.strftime('%M/%d/%Y %H:%m')}304 <ol py:if="links"> 305 <li py:for="link in reversed(links)"> 306 <a href="${link.url}">${link.title}</a> 307 posted by ${link.username} 308 at ${link.time.strftime('%M/%d/%Y %H:%m')} 313 309 </li> 314 310 </ol> … … 324 320 This template demontrates some aspects of Genshi that we've not seen so far: 325 321 * 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. 326 * 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 ` submissions` evaluates to a truth value. In this case we know that `submissions` is a list (assembled by the `Root.index()` method), so if the list is empty, the `<ol>` will be skipped.327 * Next up, we've attached a `py:for` [wiki:Documentation/xml-templates.html#looping loop] to the `<li>` element. `py:for=" submission in reversed(submissions)"`. What this does is that the `<li>` element will be repeated for every item in the `submissions` list. The `submission` variable is bound to the current item in the list on every step.322 * 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. 323 * 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. 328 324 * 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 (`${...}`). 329 325 … … 346 342 raise cherrypy.HTTPRedirect('/') 347 343 # TODO: validate the input data! 348 submission = Submission(**data)349 self.data[ submission.code] = submission344 link = Link(**data) 345 self.data[link.id] = link 350 346 raise cherrypy.HTTPRedirect('/') 351 347 … … 409 405 410 406 411 class SubmissionForm(Schema):407 class LinkForm(Schema): 412 408 username = validators.UnicodeString(not_empty=True) 413 409 url = validators.URL(not_empty=True, add_http=True, check_exists=False) … … 420 416 #!python 421 417 from formencode import Invalid 422 from geddit.form import SubmissionForm418 from geddit.form import LinkForm 423 419 }}} 424 420 … … 432 428 if cancel: 433 429 raise cherrypy.HTTPRedirect('/') 434 form = SubmissionForm()430 form = LinkForm() 435 431 try: 436 432 data = form.to_python(data) 437 submission = Submission(**data)438 self.data[ submission.code] = submission433 link = Link(**data) 434 self.data[link.id] = link 439 435 raise cherrypy.HTTPRedirect('/') 440 436 except Invalid, e: … … 590 586 @template.output('index.html') 591 587 def index(self): 592 return template.render(submissions=self.data) 588 links = sorted(self.data.values(), key=operator.attrgetter('time')) 589 return template.render(links=links) 593 590 594 591 @cherrypy.expose … … 598 595 if cancel: 599 596 raise cherrypy.HTTPRedirect('/') 600 form = SubmissionForm()597 form = LinkForm() 601 598 try: 602 599 data = form.to_python(data) 603 submission = Submission(**data)604 self.data .append(submission)600 link = Link(**data) 601 self.data[link.id] = link 605 602 raise cherrypy.HTTPRedirect('/') 606 603 except Invalid, e: … … 723 720 <p><a href="/submit/">Submit new link</a></p> 724 721 725 <ol py:if=" submissions">726 <li py:for=" submission in submissions">727 <a href="${ submission.url}">${submission.title}</a>728 posted by ${ submission.username}729 at ${ submission.time.strftime('%M/%d/%Y %H:%m')}722 <ol py:if="links"> 723 <li py:for="link in links"> 724 <a href="${link.url}">${link.title}</a> 725 posted by ${link.username} 726 at ${link.time.strftime('%M/%d/%Y %H:%m')} 730 727 </li> 731 728 </ol>