Changes between Version 61 and Version 62 of GenshiTutorial
- Timestamp:
- Sep 1, 2007, 12:45:03 AM (17 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
GenshiTutorial
v61 v62 384 384 385 385 <form action="" method="post"> 386 <table summary=""><t r>386 <table summary=""><tbody><tr> 387 387 <th><label for="username">Your name:</label></th> 388 388 <td><input type="text" id="username" name="username" /></td> … … 390 390 <th><label for="url">Link URL:</label></th> 391 391 <td><input type="text" id="url" name="url" /></td> 392 </tr> 393 <tr> 392 </tr><tr> 394 393 <th><label for="title">Title:</label></th> 395 394 <td><input type="text" name="title" /></td> 396 </tr></table> 397 <div> 398 <input type="submit" value="Submit" /> 399 <input type="submit" name="cancel" value="Cancel" /> 400 </div> 395 </tr><tr> 396 <td></td> 397 <td> 398 <input type="submit" value="Submit" /> 399 <input type="submit" name="cancel" value="Cancel" /> 400 </td> 401 </tr></tbody></table> 401 402 </form> 402 403 … … 427 428 url = validators.URL(not_empty=True, add_http=True, check_exists=False) 428 429 title = validators.UnicodeString(not_empty=True) 429 }}} 430 431 Now let's use that class in the `Root.submit()` method. First add the following to the top of `geddit/controller.py`: 430 431 432 class CommentForm(Schema): 433 username = validators.UnicodeString(not_empty=True) 434 content = validators.UnicodeString(not_empty=True) 435 }}} 436 437 Now let's use those in the `Root.submit()` method. First add the form classes, as well as the `Invalid` exception type used by !FormEncode, to the imports at the top of `geddit/controller.py`, which should then look something like this: 432 438 433 439 {{{ 434 440 #!python 441 import cherrypy 435 442 from formencode import Invalid 436 from geddit.form import LinkForm 443 from genshi.template import TemplateLoader 444 445 from geddit.form import LinkForm, CommentForm 446 from geddit.model import Link, Comment 437 447 }}} 438 448 … … 473 483 <body> 474 484 <div id="header"> 475 <h1> Geddit</h1>485 <h1>Submit new link</h1> 476 486 </div> 477 487 478 <h2>Submit new link</h2>479 488 <form action="" method="post"> 480 <table summary=""><t r>489 <table summary=""><tbody><tr> 481 490 <th><label for="username">Your name:</label></th> 482 491 <td> … … 490 499 <span py:if="'url' in errors" class="error">${errors.url}</span> 491 500 </td> 492 </tr> 493 <tr> 501 </tr><tr> 494 502 <th><label for="title">Title:</label></th> 495 503 <td> … … 497 505 <span py:if="'title' in errors" class="error">${errors.title}</span> 498 506 </td> 499 </tr></table> 500 <div> 501 <input type="submit" value="Submit" /> 502 <input type="submit" name="cancel" value="Cancel" /> 503 </div> 507 </tr><tr> 508 <td></td> 509 <td> 510 <input type="submit" value="Submit" /> 511 <input type="submit" name="cancel" value="Cancel" /> 512 </td> 513 </tr></tbody></table> 504 514 </form> 505 515 … … 518 528 But there's a problem here: Note how the input values have vanished from the form! We'd have to repopulate the form manually from the data submitted so far. We could do that by adding the required `value=""` attributes to th text fields in the template, but Genshi provides a more elegant way: the [wiki:Documentation/filters.html#html-form-filler HTMLFormFiller] steam filter. Given a dictionary of values, it can automatically populate HTML forms in the template output stream. 519 529 520 To enable this functionality, first you'll need to add the import `from genshi.filters import HTMLFormFiller` to the `genshi/controller.py` file. Next, update the bottom lines of the `Root.submit()` method implementation so that they look as follows: 530 To enable this functionality, first you'll need to add the following import to the `genshi/controller.py` file: 531 532 {{{ 533 #!python 534 from genshi.filters import HTMLFormFiller 535 }}} 536 537 Next, update the bottom lines of the `Root.submit()` method implementation so that they look as follows: 521 538 522 539 {{{ … … 633 650 }}} 634 651 635 As you can see here, the code is now less repetitive: there's a simple decorator to define which template should be used, and the `render()` produces the template out stream which can then be further processed if necessary.652 As you can see here, the code is now less repetitive: there's a simple decorator to define which template should be used, and the `render()` function produces the template output stream which can then be further processed if necessary. 636 653 637 654 … … 644 661 Match templates in Genshi turn this up side down. They are conceptually similar to running an XSLT transformation over your template output: you create rules that match elements in the template output stream based on XPath patterns. Whenever there is a match, the matched content is replaced by what the match template produces. This sounds complicated in theory, but is fairly intuitive in practice, so let's look at a concrete example. 645 662 646 Let's create a layout template first: in the `geddit/templates/` directory, add a file named `layout.html`, with the following content:663 In the `geddit/templates/` directory, add a file named `layout.html`, with the following content: 647 664 648 665 {{{ … … 655 672 <head py:attrs="select('@*')"> 656 673 <title py:with="title = list(select('title/text()'))"> 657 geddit<py:if test="title">: ${title}</py:if>674 Geddit<py:if test="title">: ${title}</py:if> 658 675 </title> 659 676 <link rel="stylesheet" href="${url('/media/layout.css')}" type="text/css" /> … … 743 760 </head> 744 761 <body> 745 < p><a class="action" href="/submit/">Submit new link</a></p>762 <h1>News</h1> 746 763 747 764 <ol py:if="links"> … … 751 768 </li> 752 769 </ol> 770 771 <p><a class="action" href="/submit/">Submit new link</a></p> 753 772 </body> 754 773 </html> 755 774 }}} 756 775 757 Also change the `submit.html` template analogously, by adding the namespace prefix, the `<xi:include>` element, and by removing the header and footer `<div>`s. 758 759 Speaking of “layout”, you can see that we've added references to some static resources in the layout template: there's an embedded image as well as a linked stylesheet and javascript file. [http://svn.edgewall.org/repos/genshi/trunk/examples/tutorial/geddit/static Download] those files and put them in your `geddit/static/` directory. 776 Also change the `submit.html` template analogously, by adding the namespace prefix, the `<xi:include>` element, and by removing the header and footer `<div>`s: 777 778 {{{ 779 #!genshi 780 <html xmlns="http://www.w3.org/1999/xhtml" 781 xmlns:xi="http://www.w3.org/2001/XInclude" 782 xmlns:py="http://genshi.edgewall.org/"> 783 <xi:include href="layout.html" /> 784 <head> 785 <title>Submit new link</title> 786 </head> 787 <body> 788 <h1>Submit new link</h1> 789 790 <form action="" method="post"> 791 <table summary=""><tbody><tr> 792 <th><label for="username">Your name:</label></th> 793 <td> 794 <input type="text" id="username" name="username" /> 795 <span py:if="'username' in errors" class="error">${errors.username}</span> 796 </td> 797 </tr><tr> 798 <th><label for="url">Link URL:</label></th> 799 <td> 800 <input type="text" id="url" name="url" /> 801 <span py:if="'url' in errors" class="error">${errors.url}</span> 802 </td> 803 </tr> 804 <tr> 805 <th><label for="title">Title:</label></th> 806 <td> 807 <input type="text" name="title" /> 808 <span py:if="'title' in errors" class="error">${errors.title}</span> 809 </td> 810 </tr><tr> 811 <td></td> 812 <td> 813 <input type="submit" value="Submit" /> 814 <input type="submit" name="cancel" value="Cancel" /> 815 </td> 816 </tr></tbody></table> 817 </form> 818 819 </body> 820 </html> 821 }}} 822 823 And speaking of “layout”, you can see that we've added references to some static resources in the layout template: there's an embedded image as well as a linked stylesheet and javascript file. [http://svn.edgewall.org/repos/genshi/trunk/examples/tutorial/geddit/static Download] those files and put them in your `geddit/static/` directory. 760 824 761 825 When you reload the front page in your browser, you should now see something similar to the following: … … 853 917 At this point you should be able to see the number of comments on the start page, click on that link to get to the details page, where you should see all comments listed for the corresponding link submission. That page also contains a link for submitting additional comments, and that's what we'll need to set up next. 854 918 855 First, we need to add a form for submitting comments to `geddit/form.py`. At the bottom of that file, add the following class: 856 857 {{{ 858 #!python 859 class CommentForm(Schema): 860 username = validators.UnicodeString(not_empty=True) 861 content = validators.UnicodeString(not_empty=True) 862 }}} 863 864 And add a corresponding import to `geddit/controller.py`, which should then have a line like this somewhere at the top: 865 866 {{{ 867 #!python 868 from geddit.form import LinkForm, CommentForm 869 }}} 870 871 Now we need to add the method for handling comment submissions to our `Root` object. It should look like this: 919 We need to add the method for handling comment submissions to our `Root` object. It should look like this: 872 920 873 921 {{{