Wed Development - Dynamically Generated News Index

Jean-Paul Calderone exarkun at divmod.com
Mon Dec 19 00:05:59 EST 2005


On 18 Dec 2005 12:27:55 -0800, infidel02 at lycos.com wrote:
>Hi Jean-Paul,
>
>I am a bit lost in you code.  Is it possible for you to step through
>it?

For in depth-assistance, it would probably be best to continue on twisted-web at twistedmatrix.com.  You might also want to check out some of the links on <http://divmod.org/trac/wiki/DivmodNevow>.  There is also a friendly, helpful IRC channel on freenode: #twisted.web.

I'll give a brief overview of what's going on, though:

  from nevow import rend, loaders, tags

  # Subclass rend.Page - this is the base class for pretty 
  # much anything that represents an entire HTTP Resource
  class NewsIndex(rend.Page):

      # Set the template for this page.  Since it's just a 
      # throw-away example, use some really cheesy stan (the 
      # stuff with the square brackets).  The below template 
      # turns into something like
      # <html><body>[whatever render_index returns]</body></html>
      docFactory = loaders.stan(tags.html[
          tags.body(render=tags.directive('index'))])

      # Boring initializer that takes a database connection 
      # pool to issue queries against.
      def __init__(self, connpool):
          super(NewsIndex, self).__init__()
          self.connpool = connpool

      # "model" function - doesn't know about web, just 
      # knows the db schema; returns a Deferred that fires
      # with information about all the articles in the database.
      def _retrieveIndex(self):
          return self.connpool.runQuery(
              "SELECT articleId, articleTitle, articleImage FROM articles")

      # Another model function.  This one gets the body text for
      # one particular article.
      def _retrieveArticle(self, articleId):
          return self.connpool.runQuery(
              "SELECT articleBody FROM articles WHERE articleId = ?",
              (articleId,))

      # The render function for the guts of the index page.  This 
      # uses one of the model functions to get all the articles in 
      # the database.  Since _retrieveIndex returns a Deferred, it 
      # doesn't use the results right away - instead of defines a 
      # lambda that will get invoked with the article information 
      # when it is received.

      # There's some display logic here, too.  Some more stan, which
      # renders to something like:
      # <div>
      #   <a href="<articleID>">
      #     <img src="<article image>" />
      #     article title
      #   </a>
      # </div>
      # for each article in the index
      def render_index(self, ctx, data):
          return self._retrieveIndex().addCallback(lambda index: ctx.tag[[
              tags.div[
                  tags.a(href=articleID)[
                      tags.img(src=articleImage),
                      articleTitle]]
              for (articleID, articleTitle, articleImage)
              in index]])

      # Allow this Resource to have children.  Above, we generated links
      # to "articleID" for each article in the index.  This function
      # handles those links by using the other model function to retrieve
      # the body of the requested article and return another Page subclass
      # instance for it.
      def childFactory(self, ctx, name):
          return self._retrieveArticle(name).addCallback(lambda articleBody:
              ArticlePage(articleBody))


  # The other display class.  This one is pretty boring.  It just 
  # displays the body of an article.
  class ArticlePage(rend.Page):
      docFactory = loaders.stan(tags.html[
          tags.body(render=tags.directive('article'))])

      def __init__(self, articleBody):
          super(ArticlePage, self).__init__()
          self.articleBody = articleBody

      # Just spit out the article body.  Note I changed one thing here.  
      # In the original version, I left out the "ctx.tag[...]" around 
      # the article body.  This would have removed the <body> tag from 
      # the resulting document!  Ooops.  I also left this out of 
      # render_index above (so I've added it there as well).
      def render_article(self, ctx, data):
          return ctx.tag[self.articleBody]

  from twisted.enterprise import adbapi

  # Whatever DB-API 2.0 stuff you want
  cp = adbapi.ConnectionPool('pypgsql', ...)

  from twisted.application import service, internet
  from nevow import appserver

  application = service.Application("News Site")
  webserver = appserver.NevowSite(NewsIndex(cp))
  internet.TCPServer(80, webserver).setServiceParent(application)

  # Run with twistd -noy <whatever you name this file>

Hope this helps,

Jean-Paul



More information about the Python-list mailing list