Edgewall Software

Changes between Version 40 and Version 41 of GenshiTutorial


Ignore:
Timestamp:
Aug 30, 2007, 8:55:10 PM (17 years ago)
Author:
cmlenz
Comment:

Added the comments section

Legend:

Unmodified
Added
Removed
Modified
  • GenshiTutorial

    v40 v41  
    512512Now, all entered values are preserved when validation errors occur. Note that the form is populated as the template is being generated, there is no reparsing and reserialization of the output.
    513513
    514 == Enhancing the Application ==
     514== Improving the Application ==
    515515
    516516=== Factoring out the Templating ===
     
    744744=== Implementing Comments ===
    745745
     746We're still missing an important bit of functionality: people should be able to comment on submitted links. Three things are needed to implement that:
     747 * a detail view of a link, showing all comments made so far,
     748 * a way to get to that page from the list of links, and,
     749 * a form to add new comments.
     750
     751Note that on the model side we're covered, there's already a `Comment` class in `geddit.model`, and we even have two comments in our database already.
     752
     753So let's start by extending the `index.html` template to show how many comments there are so far, and make that a link to the detail page. Change your `geddit/templates/index.html` file to match the following:
     754
     755{{{
     756#!genshi
     757<!DOCTYPE html>
     758<html xmlns="http://www.w3.org/1999/xhtml"
     759      xmlns:xi="http://www.w3.org/2001/XInclude"
     760      xmlns:py="http://genshi.edgewall.org/">
     761  <xi:include href="layout.html" />
     762  <head>
     763    <title>News</title>
     764  </head>
     765  <body>
     766    <h1>News</h1>
     767    <p><a href="${url('/submit/')}">Submit new link</a></p>
     768
     769    <ol py:if="links" class="links">
     770      <li py:for="link in links">
     771        <a href="${link.url}">${link.title}</a>
     772        posted by ${link.username} at ${link.time.strftime('%m/%d/%Y %H:%M')}
     773        <div class="info">
     774          <a href="${url('/info/%s/' % link.id)}">
     775            ${len(link.comments)} comments
     776          </a>
     777        </div>
     778      </li>
     779    </ol>
     780  </body>
     781</html>
     782}}}
     783
     784We've added a `<div class="info">` for every link in the list, each containing the number of comments, and linking to the detail page.
     785
     786Of couse, if you click on those links, you'll get an error page: we haven't implemented the `info()` view yet!
     787
     788Let's do that now. Add the following method to the `Root` class:
     789
     790{{{
     791#!python
     792    @cherrypy.expose
     793    @template.output('info.html')
     794    def info(self, code):
     795        link = self.data.get(code)
     796        if not link:
     797            raise cherrypy.NotFound()
     798        return template.render(link=link)
     799}}}
     800
     801And then add the needed temlate `geddit/templates/info.html` with the following content:
     802
     803{{{
     804#!genshi
     805<!DOCTYPE html>
     806<html xmlns="http://www.w3.org/1999/xhtml"
     807      xmlns:xi="http://www.w3.org/2001/XInclude"
     808      xmlns:py="http://genshi.edgewall.org/">
     809  <xi:include href="layout.html" />
     810  <head>
     811    <title>${link.title}</title>
     812  </head>
     813  <body>
     814    <h1>${link.title}</h1>
     815    <a href="${link.url}">${link.url}</a><br />
     816    posted by ${link.username} at ${link.time.strftime('%m/%d/%Y %H:%M')}<br />
     817    <a href="${url('/comment/%s/' % link.id)}">comment</a>
     818    <ul py:if="link.comments" class="comments">
     819      <li py:for="comment in link.comments">
     820        <strong>${comment.username}</strong>
     821        at ${comment.time.strftime('%m/%d/%Y %H:%M')}
     822        <blockquote>${comment.content}</blockquote>
     823      </li>
     824    </ul>
     825  </body>
     826</html>
     827}}}
     828
     829At 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.
     830
     831First, we need to add a form for submitting comments to `geddit/form.py`. At the bottom of that file, add the following class:
     832
     833{{{
     834#!python
     835class CommentForm(Schema):
     836    username = validators.UnicodeString(not_empty=True)
     837    content = validators.UnicodeString(not_empty=True)
     838}}}
     839
     840And add a corresponding import to `geddit/controller.py`, which should then have a line like this somewhere at the top:
     841
     842{{{
     843#!python
     844from geddit.form import LinkForm, CommentForm
     845}}}
     846
     847Now we need to add the method for handling comment submissions to our `Root` object. It should look like this:
     848
     849{{{
     850#!python
     851    @cherrypy.expose
     852    @template.output('comment.html')
     853    def comment(self, code, cancel=False, **data):
     854        link = self.data.get(code)
     855        if not link:
     856            raise cherrypy.NotFound()
     857        if cherrypy.request.method == 'POST':
     858            if cancel:
     859                raise cherrypy.HTTPRedirect('/info/%s' % link.id)
     860            form = CommentForm()
     861            try:
     862                data = form.to_python(data)
     863                comment = link.add_comment(**data)
     864                raise cherrypy.HTTPRedirect('/info/%s' % link.id)
     865            except Invalid, e:
     866                errors = e.unpack_errors()
     867        else:
     868            errors = {}
     869
     870        return template.render(link=link, comment=None,
     871                               errors=errors) | HTMLFormFiller(data=data)
     872
     873}}}
     874
     875Last but not least, we need the template that renders the comment submission form. Inside `geddit/templates`, add a file named `comment.html`, and insert the following content:
     876
     877{{{
     878#!genshi
     879<!DOCTYPE html>
     880<html xmlns="http://www.w3.org/1999/xhtml"
     881      xmlns:xi="http://www.w3.org/2001/XInclude"
     882      xmlns:py="http://genshi.edgewall.org/">
     883  <xi:include href="layout.html" />
     884  <head>
     885    <title>Comment on “${link.title}”</title>
     886  </head>
     887  <body>
     888    <h1>Comment on “${link.title}”</h1>
     889    <p py:if="comment">
     890      In reply to <strong>${comment.username}</strong>
     891      at ${comment.time.strftime('%M/%d/%Y %H:%m')}:
     892      <blockquote>${comment.content}</blockquote>
     893    </p>
     894    <form action="" method="post">
     895      <table summary=""><tbody><tr>
     896        <th><label for="username">Your name:</label></th>
     897        <td>
     898          <input type="text" id="username" name="username" />
     899          <span py:if="'username' in errors" class="error">${errors.username}</span>
     900        </td>
     901      </tr><tr>
     902        <th><label for="comment">Comment:</label></th>
     903        <td>
     904          <textarea id="comment" name="content" rows="6" cols="50"></textarea>
     905          <span py:if="'content' in errors" class="error"><br />${errors.content}</span>
     906        </td>
     907      </tr></tbody></table>
     908      <div>
     909        <input type="submit" value="Submit" />
     910        <input type="submit" name="cancel" value="Cancel" />
     911      </div>
     912    </form>
     913  </body>
     914</html>
     915}}}
     916
     917Phew! We should be done with the commenting now. Play around with the application a bit to get a feel for what we've achieved so far. The next section will look into various things that can be done to further improve the application.
     918
     919== Advanced Topics ==
     920
     921=== Allowing Markup in Comments ===
     922
    746923TODO
    747924
    748 == Advanced Topics ==
    749 
    750 === Allowing Markup in Comments ===
     925=== Ajaxifyied Commenting ===
    751926
    752927TODO
    753928
    754 === Ajaxifyied Commenting ===
     929=== Adding an Atom Feed ===
    755930
    756931TODO
    757932
    758 === Adding an Atom Feed ===
     933== Summary ==
    759934
    760935TODO
    761 
    762 == Summary ==
    763 
    764 TODO