Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Thursday, June 19, 2008

Python 2.6 and 3.0 Beta 1 Released.

- Link

Get them while they're hot!

2.6

3.0 Beta

Sunday, March 30, 2008

Update Google Talk status with Twitter

I've had this idea in my head for a while and just got it to work this morning.

Basically you send a tweet from Twitter and this script runs, picks up your current twitter status, and if need be, updates your gChat status. I'm working on a service version of this where you could use gpowered.net to do all this for you. Stay tuned =) If I change the version of the script that I have running in the service, you will be able to see the source code that I have checked in here

For those of you that don't know what Twitter is:
"Twitter is a free social networking and micro-blogging service that allows users to send "updates" (or "tweets"; text-based posts, up to 140 characters long) to the Twitter website, via short message service (e.g. on a cell phone), instant messaging, or a third-party application such as Twitterrific or Facebook. Updates are displayed on the user's profile page and instantly delivered to other users who have signed up to receive them. The sender can restrict delivery to those in his or her circle of friends (delivery to everyone is the default). Users can receive updates via the Twitter website, instant messaging, SMS, RSS, email or through an application. For SMS, four gateway numbers are currently available: short codes for the USA, Canada, and India, as well as a UK number for international use. Several third parties offer posting and receiving updates via email." (Wikipidia)


Requirements:
xmpppy
python-twitter


import sys, xmpp, os, twitter

class Twitter2gChat:
    
    twitter_login = os.environ['TWITTER_LOGIN']
    twitter_pass = os.environ['TWITTER_PASS']
    google_login = os.environ['GOOGLE_LOGIN']
    google_pass = os.environ['GOOGLE_PASS']

    twitter_status = None
    updated = False
    catches = 0
    
    #keep looping and wait for xmpp response
    def GoOn(self,conn):
        while self.StepOn(conn):
            pass
    
    #keep listening for responses
    def StepOn(self,conn):
        try:
            conn.Process(1)
        except KeyboardInterrupt:
                return 0
        return 1

    #handle responses
    def iqHandler(self, conn,iq_node):
        print 'in iqHandler'
        self.catches = self.catches + 1
        
        #we have looped enough, die
        if self.catches == 4:
            print 'i think we did it'
            sys.exit(0)
        
        #print response, don't need to send anything back    
        if self.updated == True:
            print iq_node
        
        #havn't updated yet, sent status update
        else:
            #we can build of response
            node = iq_node.getChildren()[0]
            
            #remove what we don't ned
            node.delAttr('status-list-max')
            node.delAttr('status-max')
            node.delAttr('status-list-contents-max')
            iq_node.delAttr('from')
            iq_node.delAttr('type')
            iq_node.delAttr('to')
           
           #update the current status
            curr_status = node.getChildren()[0]
            
            #no need to update
            if curr_status.getData() == self.twitter_status:
                print 'status is already tweet'
                sys.exit(0)
                
            curr_status.setData(self.twitter_status)

            #set response
            iq_node.setType('set')
            
            print 'sending'
            print iq_node
            self.updated = True
            conn.send(iq_node)
            print 'end of iqHandler\n\n'

    #start talking to the server and update status
    def updateGtalkStatus(self):
        
        #connect
        jid=xmpp.protocol.JID(self.google_login)
        cl=xmpp.Client(jid.getDomain(),debug=[])
        if not cl.connect(('talk.google.com',5222)):
            print 'Can not connect to server.'
            sys.exit(1)
        if not cl.auth(jid.getNode(),self.google_pass):
            print 'Can not auth with server'
            sys.exit(1)
            
        #build query to get current status
        iq = xmpp.Iq()
        iq.setType('get')
        iq.setTo('timothy.broder@gmail.com')

        node = xmpp.Node()
        node.setName('query')
        node.setAttr('xmlns', 'google:shared-status')

        iq.addChild(node=node) 
        print iq

        #register with server and send subscribe to status updates
        cl.RegisterHandler('iq',self.iqHandler)
        cl.send(iq)

        self.GoOn(cl)
        cl.disconnect()
        
    #get current twitter status
    def getTwitterStatus(self):
        api = twitter.Api(username=self.twitter_login, password=self.twitter_pass)
        self.twitter_status = api.GetUserTimeline(self.twitter_login, 1)[0].text
        
        #don't want to use replies
        if self.twitter_status.find('@') >= 0:
            sys.exit(0)

t = Twitter2gChat()
t.getTwitterStatus()
t.updateGtalkStatus()

Thursday, October 4, 2007

Displaying what you read from Google Reader

I've been wanting to share what I subscribe to in Google Reader and using the functions I wrote I was able to do just that. Check out the article for the full run down on the unofficial Google Reader API. This is written in python but should be easily portable to php. If i get around to it, I want to make a WordPress plugin so bloggers can share what they read with their readers. This will be followed (or in parallel depending on my mood) with a Javascript version so Blogspot users can do the same in the sidebar. On to the code!

To start off we'll just copy the functions we need from last time. Generally this is the login and SID token functions, as well as the feed list function.

from django.shortcuts import render_to_response
from django.template import Library
from elementtree import ElementTree   
import urllib
import urllib2
import re

login = 'timothy.broder@gmail.com'
password = '***'
source = 'gPowered'

google_url = 'http://www.google.com'
reader_url = google_url + '/reader'
login_url = 'https://www.google.com/accounts/ClientLogin'
token_url = reader_url + '/api/0/token'
subscription_list_url = reader_url + '/api/0/subscription/list'

#login / get SED
def get_SID():
    header = {'User-agent' : source}
    post_data = urllib.urlencode({ 'Email': login, 'Passwd': password, 'service': 'reader', 'source': source, 'continue': google_url, })
    request = urllib2.Request(login_url, post_data, header)
   
    try :
        f = urllib2.urlopen( request )
        result = f.read()
   
    except:
        print 'Error logging in'
       
    return re.search('SID=(\S*)', result).group(1)

#get results from url
def get_results(SID, url):
    header = {'User-agent' : source}
    header['Cookie']='Name=SID;SID=%s;Domain=.google.com;Path=/;Expires=160000000000' % SID
    print url
    request = urllib2.Request(url, None, header)
   
    try :
        f = urllib2.urlopen( request )
        result = f.read()
   
    except:
        print 'Error getting data from %s' % url
   
    return result

#get a specific feed.  It works for any feed, subscribed or not
def get_feed(SID, url):
    return get_results(SID, get_feed_url + url.encode('utf-8'))
   
#get a token, this is needed for modifying to reader
def get_token(SID):
    return get_results(SID, token_url)

#get a list of the users subscribed feeds
def get_subscription_list(SID):
    return get_results(SID, subscription_list_url)


Then we'll want to get rid off all the information in the feed that we don't want and load what we do into a data dictionary. After its in the dictionary, feed names and links (and the folders they are in) are ready to be displayed. As usual, I use Django to display my pages, but everything is the same up to the final return in the Feeds method. Below is an example of what each subscription looks like in the Google Reader Feed, and below that is how to process it



            feed/http://www.ubuntu.com/rss.xml
            Ubuntu
            

                
                    user/16162999404522159936/label/dev
                    dev
                
            
            1186137757794
        




class myFeed:
    def __init__(self, name, link):
        self.name = name
        self.link = link

def Feeds(request):
    SID = get_SID()
    feeds = get_subscription_list(SID)
    tree = ElementTree.fromstring(feeds)
    d = dict()   

    #loop through each feed   
    for object in tree.findall('list')[0].findall('object'):
        strings = object.findall('string')
        key = object.findall('list')[0].findall('object')[0].findall('string')[1].text
       
        #tag already exists, add to the list
        try:
            d[key].append(myFeed(strings[1].text, strings[0].text.replace('feed/', '')))
        #tag doesn't exist, create list
        except KeyError:
            d[key] = [myFeed(strings[1].text, strings[0].text.replace('feed/', ''))]

       
    return render_to_response('pages/feeds.html', {
    'feeds': d,
    })


For those of you that use django or are just curious how I end up displaying the feeds, this is what i have in my view:

My Reading

    {% for item in feeds.items %}
  • {{ item.0 }}
  • {% endfor %}


Again, too see what I subscribe to, click here

Wednesday, August 29, 2007

HOWTO: Getting the Numer of Diggs from Digg (Python)

After 2 of my posts were on the Digg front page this morning (Thank you all very much to those that dugg them), I took my first look into the Digg API. I wanted a way to take a quick look to see how many Diggs certain stories were getting. In some ways it is similar to GData: make a call to a URL, get some XML back, parse it, etc. It does, however, feel lighter, probably due to its streamlined nature. It has one purpose, get information off of Digg. Using this, I've added a section in the Post List section of gPowered.net that shows the Diggs of a few of the articles that I have submitted on Digg.

The API is broken into 5 main sections or endpoints. Each of these will return related types of data:
- Stories
- Events
- Users
- Topics
- Errors

In this quick HOWTO I'm going to take a quick look into the Stories endpoint so I can display the number of Diggs specific stories have. We'll start off by making a small class to hold our returned data (useful to send to a template or just for working with later on. We don't want to keep having to hit the ElementTree to get data out). All of the calls will be send to 'http://services.digg.com/'. In this example I will only be querying 'http://services.digg.com/story/{story clean title}'.

import httplib2  
from elementtree import ElementTree  

#for storing
class MyDigg:
 def __init__(self, title, link, digg, diggs):
  self.title = title
  self.link = link
  self.digg = digg
  self.diggs = diggs
 
 def __str__(self):
  return self.title + ' ' + self.diggs

#stories to get diggs of  
posts = [
 'Google_NOT_releasing_it_s_Goobuntu_Desktop_OS_STOP_DIGGING_IT', 
 'New_Digg_Home_Page_breaks_the_Linux_section_on_IE',
 'Google_Reader_API_Functions'
 ]
 
#hold returned info
my_diggs = []

#all calls go through this
digg_service = 'http://services.digg.com/'

#just looking at stories
service_endpoint = digg_service + 'story/%s'

#only need 1 result back
trailer = '?count=1&appkey=http%3A%2F%2Fgpowered.blogspot.com'

#keep track of total diggs
total_diggs = 0


After we are set up, we will want to loop through each story we want to get Digg data for. Add the well formed title into the query string, and send it to the Digg service. Then, parse the response, and get the information we need.

for story in posts:
 curr_story = service_endpoint % story
 url = curr_story + trailer

 h = httplib2.Http() 
 resp, content = h.request(url, "GET", body="nt", headers={'content-type':'text/plain'} )
 
 story = ElementTree.fromstring(content).findall('story')[0]
 
 d = MyDigg(story.findall('title')[0].text, story.get('link'), story.get('href'), story.get('diggs'))
 total_diggs = total_diggs + int(d.diggs)
 my_diggs.append(d)
 print d

print 'Total: ' + str(total_diggs)


And that's that. my_diggs now has all the information we need!

Wednesday, August 22, 2007

HOWTO: Google Reader API Functions

I've been wanting an API for Google reader since I started using it, and especially since i started gPowered so I could display a list of the feeds I read on the site. The official word on an API for reader is "It's coming in a few weeks," but that was back in late 2005. The reason being that at the time, the URLs the API would use were going to change a lot. So, after a bit of research and coding I came up with some python functions to do the job.



The first step was authenticating against Google accounts without using the client library. The Python Gdata Library makes login very easy but Reader isn't part of the Client Library yet (maybe I'll try to add it, we'll see...) but this was the method I was using for gdata and python pre-Client Library, and the principles still hold true for working with Reader. Thankfully, most of the research for working with the 'Reader API' was done for me already by Niall Kennedy. This is an unofficial, unsupported API and the URLs for some of the queries have changed since the writing of that article. Here we go...

We're going to use urllib(2) to handle the communication with this one. I rather would have used httplib, but I was having trouble with the authentication cookie. Each retrieval has its own URL to query against

import urllib
import urllib2
import re

login = 'timothy.broder@gmail.com'
password = '****'
source = 'gPowered'

google_url = 'http://www.google.com'
reader_url = google_url + '/reader'
login_url = 'https://www.google.com/accounts/ClientLogin'
token_url = reader_url + '/api/0/token'
subscription_list_url = reader_url + '/api/0/subscription/list'
reading_url = reader_url + '/atom/user/-/state/com.google/reading-list'
read_items_url = reader_url + '/atom/user/-/state/com.google/read'
reading_tag_url = reader_url + '/atom/user/-/label/%s'
starred_url = reader_url + '/atom/user/-/state/com.google/starred'
subscription_url = reader_url + '/api/0/subscription/edit'
get_feed_url = reader_url + '/atom/feed/'


When we authenticate against Google Reader with a gmail account and password in the browser, a cookie is stored. We'll have to recreate the values in this cookie. The static values are the Domain (.google.com), the Path (/), and Expires (we'll use 160000000000). The unique value, based on the current login session, is the SID (Session ID?), which we will need to retrieve. We'll do the login and retrieval in the same function:

#login / get SED
def get_SID():
    header = {'User-agent' : source}
    post_data = urllib.urlencode({ 'Email': login, 'Passwd': password, 'service': 'reader', 'source': source, 'continue': google_url, })
    request = urllib2.Request(login_url, post_data, header)
    
    try :
        f = urllib2.urlopen( request )
        result = f.read()
    
    except:
        print 'Error logging in'
        
    return re.search('SID=(\S*)', result).group(1)


We'll also need a function that can handle any of those URLs, create the header, attach a cookie to it, and retrieve the data from Google. I left the return as a raw data string so you could use whatever XML parsing library you want. I personally like using ElementTree.

#get results from url
def get_results(SID, url):
    header = {'User-agent' : source}
    header['Cookie']='Name=SID;SID=%s;Domain=.google.com;Path=/;Expires=160000000000' % SID

    request = urllib2.Request(url, None, header)
    
    try :
        f = urllib2.urlopen( request )
        result = f.read()
    
    except:
        print 'Error getting data from %s' % url
    
    return result


The following methods are the calls that I've gotten working so far; I'm going to keep working on the 'edit' functions, like adding, removing feeds, changing tags, etc. See the comments for what they do. Note: Any edit against the API needs to send over a changing token as part of the call

#get a token, this is needed for modifying to reader
def get_token(SID):
    return get_results(SID, token_url)

#get a specific feed.  It works for any feed, subscribed or not
def get_feed(SID, url):
 return get_results(SID, get_feed_url + url.encode('utf-8'))

#get a list of the users subscribed feeds
def get_subscription_list(SID):
    return get_results(SID, subscription_list_url)

#get a feed of the users unread items    
def get_reading_list(SID):
    return get_results(SID, reading_url)

#get a feed of the users read items    
def get_read_items(SID):
    return get_results(SID, read_items_url)
    
#get a feed of the users unread items of a given tag    
def get_reading_tag_list(SID, tag):
        tagged_url = reading_tag_url % tag
        return get_results(SID, tagged_url.encode('utf-8'))
        
#get a feed of a users starred items/feeds
def get_starred(SID):
    return get_results(SID, starred_url)

#subscribe of unsubscribe to a feed    
def modify_subscription(SID, what, do):
    url = subscription_url + '?client=client:%s&ac=%s&s=%s&token=%s' % ( login, do.encode('utf-8'), 'feed%2F' + what.encode('utf-8'), get_token(SID) )
    print url
    return get_results(SID, url)
    
#subscribe to a feed
def subscribe_to(SID, url):
    return modify_subscription(SID, url, 'subscribe')

#unsubscribe to a feed
def unsubscribe_from(SID, url):
    return modify_subscription(SID, url, 'unsubscribe')


Example usage:

SID = get_SID()
print get_subscription_list(SID)
#print get_reading_list(SID)
#print get_read_items(SID)
#print get_reading_tag_list(SID, 'me')
#print get_reading_tag_list(SID, 'nada-mas')
#print get_starred(SID)
#print get_token(SID)

#test_feed = 'http://picasaweb.google.com/data/feed/base/user/timothy.broder/albumid/5101347429735335089?kind=photo&alt=rss&hl=en_US'

#print subscribe_to(SID, test_feed)
#returns ok but I don't see the feed in reader?

#print get_feed(SID, test_feed)


Like I said, I'd like to keep going with this and get the edit functionality to work better. I'm also going to take a look into the Client Library and see if I could set this up as a patch that people could use if they wanted to use the API.

Saturday, August 11, 2007

HOWTO: Pulling Google Bookmarks with Python

I love using Google Bookmarks (usually with the Google Toolbar) because it lets me get to my bookmarks at home on my laptop or desktop, at work, or anywhere. It's great. Now I'm using those bookmarks to power the links section of gPowered.net
First we're going to need the httplib2 library so we can authenticate against Google and grab the bookmark feed and then the ElementTree to help process the rss feed.

import httplib2
from elementtree import ElementTree

Then we'll setup the link to pull the rss from, authenticate against the request, and pull back the feed

login = "timothy.broder@gmail.com"  
password = "*****"
url = 'https://www.google.com/bookmarks/?output=rss&num=1000'  
  
h = httplib2.Http()  
h.add_credentials(login, password)  
 
resp, content = h.request(url, "POST", body="nt", headers={'content-type':'text/plain'} )

I figured for this a hashmap (or dictionary) would work well using the tags on the bookmarks as keys, pointing to lists of bookmarks. Then when we display them, just iterate through the keys. I also kept a list of the keys to make sorting faster later on. So we define our objects and then loop through the rss object pulling out the tags for keys, the names of the links, and the urls. I define a small Bookmark class which holds a name and url which will go into the hashmap to make storing the bookmark's easier. When I try to add a bookmark to the dict's list I try to append it, if the key(tag) doesn't exist I know I have to start a new list.

class Bookmark:
 def __init__(self, name, link):
  self.name = name
  self.link = link
  
d = dict()
sort_keys = []
for item in tree.findall('item'):
 key = item.findtext('{http://www.google.com/searchhistory}bkmk_label')
 if (key != None) and (key != 'gpowered') and (key != 'BP') and (key != 'Quick Searches') and (key != 'Me'):
  title = item.findtext('title')
  link = item.findtext('link')
  try:
   d[key].append(Bookmark(title.encode('utf-8'), link))
  except KeyError:
   d[key] = [Bookmark(title.encode('utf-8'), link)]
   sort_keys.append(key)

Then we'll sort the key list and the list of each key. To do this we need a small function that defines how to sort a bookmark

def bookmark_compare(a, b):
 return cmp(a.name, b.name)

sort_keys.sort() 
for key in sort_keys:
 d[key].sort(bookmark_compare)

Check out the static HTML version Here. I also made a fancier version using YUI's TreeView

HOWTO: Getting a list of post titles from blogger (Python)

This will be a quick one on how to pull the titles from your blog. I'm using it to Lists the posts I have available on gPowered.net. Firstly we'll set up our imports and call to the blogger service.

from elementtree import ElementTree 
from gdata import service
import gdata
import atom
import getopt
import sys

blog_id = 413573351281770670
blogger_service = service.GDataService('timothy.broder@gmail.com', '*****')
blogger_service.source = 'Blogger_Python_Sample-1.0'
blogger_service.service = 'blogger'
blogger_service.server = 'www.blogger.com'
blogger_service.ProgrammaticLogin()

For this query we're going to use the summary feed because all we really need for this is the titles, not the full posts:

query = service.Query()
query.feed = '/feeds/' + str(blog_id) + '/posts/summary'
feed = blogger_service.Get(query.ToUri())

Then I just do a little counting so I can use the links on my site. All the information we need is in feed.entry

curr_id = int(feed.total_results.text)
for entry in feed.entry:
 entry.my_id = curr_id
 curr_id -= 1

Thursday, August 9, 2007

Quick Docs Api Example (python)

To use the gdata docs python client you need to upgrade to 1.0.7 or higher. First thing is to import the modules you'll need.

import gdata.docs.service
import gdata.docs

Then, set up the usual authentication parameters for the client.

gd_client = gdata.docs.service.DocsService()
gd_client.email = 'timothy.broder'
gd_client.password = '*****'
gd_client.source = 'gpowered-docs-list-ex'
gd_client.ProgrammaticLogin()

The most basic query will just return all of your documents

feed = gd_client.GetDocumentListFeed()

However, if we want to display just the spreadsheets, we build the query like this:

q = gdata.docs.service.DocumentQuery(categories=['spreadsheet'])
feed = gd_client.Query(q.ToUri())

Finally, we output the titles

if(len(feed.entry) == 0):
        print 'No entries in feed.\n'
for i, entry in enumerate(feed.entry):
        print '%s %s (%s)' % (i+1, entry.title.text.encode('UTF-8'))

If we wanted to, we could also import the DateTime library and show when the document was last updated

import gdata.docs.service
import gdata.docs

from mx import DateTime

gd_client = gdata.docs.service.DocsService()
gd_client.email = 'timothy.broder'
gd_client.password = '*****'
gd_client.source = 'gpowered-docs-list-ex'
gd_client.ProgrammaticLogin()

q = gdata.docs.service.DocumentQuery(categories=['spreadsheet'])
#feed = gd_client.GetDocumentListFeed()
feed = gd_client.Query(q.ToUri())

if(len(feed.entry) == 0):
        print 'No entries in feed.\n'
for i, entry in enumerate(feed.entry):
        dt = DateTime.ISO.ParseDateTimeUTC(entry.updated.text)
        print '%s %s (%s)' % (i+1, entry.title.text.encode('UTF-8'), dt.strftime('%m/%d/%Y %I:%M %p'))


For me this outputs:
1 TDP2006 Contact Info (11/18/2006 05:41 AM)
2 contact info (07/23/2006 08:15 PM)
3 Tim and Rob (08/09/2007 10:18 PM)
4 nyc happy hour spreadsheet (07/04/2007 08:25 PM)
5 public_spring_2006_roster (10/16/2006 12:40 AM)
6 dax2006 (11/12/2006 11:23 PM)
7 project dream (07/13/2007 03:54 AM)
8 Stuff Tim should get (06/13/2007 01:53 AM)
9 Erg Test Results - 9/26 (10/15/2006 01:02 AM)
10 Head of the Charles Regatta Itineary (10/17/2006 04:54 PM)
11 tvshows (11/02/2006 11:44 PM)
12 HF (10/01/2006 03:36 PM)

Wednesday, July 18, 2007

HOWTO: Displaying Blogger feeds with Python

This first HOWTO is going to cover how I did the basic structure of the posts section of gPowered: pulling from blogger. The main functions we'll need are to show a range of posts, a single post, and a function to get the total number of posts that are in the blog. The reason I try to get the total number is so the different pages can be bookmarkable. When retrieving a GData feed from blogger. Entry 1 in the feed is going to be the newest post so there is no 'id' that is going to be static, so we'll do a little math to get a number we can later use as the id. I use Django to handle rendering the python to the browser. I probably won't get into other methods.

To start out you'll have to grab the following modules.
- the gdata python client
- ElementTree
- mxDateTime (I used this for date formatting)

We then import the parts the we'll need (you can ignore the Django part for your own methods):

from Django.shortcuts import render_to_response

from gdata import service
import gdata
import atom
import getopt
import sys

from mx import DateTime

One of the first things we're going to have to do is authenticate with google services. There are two ways to do this: AuthSub proxy authentication which has a user login using their own credentials, and ClientLogin username/password authentication where you send a username and password. We will be using ClientLogin. First off, set your login credentials to use later.

#login info
user = 'timothy.broder@gmail.com'
password = '********'

Then we start setting up our call to the service.

#set up service
blogger_service = service.GDataService(user, password)
blogger_service.source = 'gpowered'
blogger_service.service = 'blogger'
blogger_service.server = 'www.blogger.com'
blogger_service.ProgrammaticLogin()

For more info see the blogger developer's guide with python or the Google Account Authentication documentation
After we have authenticated with Google we need to start building up our query to GData, which will return as an ElementTree of data. The first thing you'll need is your blog's id.
You can use the function in the dev guide to help you with this if you don't already know it.

def PrintUserBlogTitles(blogger_service):
  query = service.Query()
  query.feed = '/feeds/default/blogs'
  feed = blogger_service.Get(query.ToUri())

  print feed.title.text
  for entry in feed.entry:
    print "\t" + entry.title.text

After you have the blog id we can start working on the query

blog_id = 413573351281770670
feed_url = '/feeds/%s/posts/default' % str(blog_id)
query = service.Query()
query.feed = feed_url

The below function returns the total number of posts that are in the feed. We can get a small response by sending 0 for the max results. Below is the function and the small response we get from it.

#get the total number of posts for this feed
def get_total(query):
 #query for no posts
 query.max_results = '0'
 query.start_index = '1'
 
 #get back entryless feed
 feed = blogger_service.Get(query.ToUri()) 
 return int(feed.total_results.text)



 1
 0
 1
 Blogger
 Tim
 tag:blogger.com,1999:blog-413573351281770670
 
 
 
 
 gPowered
 2007-07-18T10:55:06.728-05:00


So we get the total number of posts and then we can start pulling data. Lets make a generic function, PostFrom, that can be used to show multiple posts, or just single ones, depending on what you pass to it. The start number that is passed to PostFrom has been set to the first post in the blog is considered to have an id of 1 and the latest post is the same as total_posts. This is useful so if viewers want to bookmark the page they are looking at, the post that is being displayed will not change. The following are the different functions that will make use of it.

#show latest posts
def Posts(request):
 return ListPosts(request, total_posts)

#show posts starting from a certain point 
def ListPosts(request, start):
 start = total_posts - int(start) + 1
 return PostFrom(request, start, show_num)

#show a single post
def Post(request, start):
 start = total_posts - int(start) + 1
 return PostFrom(request, start, 1)
 
def PostFrom(request, start, count):
 #query for count number of posts starting at the given post
 query.max_results = str(count)
 query.start_index = str(start)
 feed = blogger_service.Get(query.ToUri())

now we have all the data we need in the feed variable. Its been turned into an element tree so we don't have to worry about XML parsing here. Every node has become an objects and lists. Objects for single nodes(title), and lists for where there are multiple nodes of the same name (entry, link) At this stage I play with the data a little so it's easier to use in my Django template.

 #normalize data for output
 for entry in feed.entry:
  #get link for template
  entry.my_link = entry.link[0].href
  
  #id for links
  entry.my_id = curr_id
  curr_id -= 1
  
  #format published date
  dt = DateTime.ISO.ParseDateTimeUTC(entry.published.text)
  entry.my_date = dt.strftime('%m/%d/%Y')
  entry.my_time = dt.strftime('%I:%M %p') 

Of course we're going to need next and previous buttons as well. The way we've set up the math with total_posts and the start number, we only have to increment or decrement these by count (the number of posts to display on a page). I also set part of the link, as well as the page title, that I will use in my template.

 prev = total_posts - (start - count) + 1
 if prev > total_posts:
  prev = None
  
  
 next = total_posts - (start + count) + 1
 if next < 1:
  next = None
 
 #showing single post 
 if count == 1:
  link = 'post'
  title = feed.entry[0].title.text
 #listing posts
 else:
  link = 'posts'
  title = 'home'

The final part of the function is a return to the Django framework to populate my template. I'm going to get into the template more in the next post, but you now have all the information you need stored.

 return render_to_response('posts/index.html', {
  'entries': feed.entry,
  'title': title,
  'tag_link': tag_link, 
  'prev': prev,
  'next': next,  
  'link': link,
  'tab_home': True,
  })

To the template!

The first part consists of displaying the post itself, along with its relevant information

{% for entry in entries %}

  <h2><a href="/post/{{ entry.my_id }}">{{ entry.title.text }}</h2></a>
  {{ entry.content.text }}
  <p>Posted by {% for auth in entry.author %}{{ auth.name.text }}{% if not forloop.last %}, {% endif %}{% endfor %} 
  on {{ entry.my_date }} at {{ entry.my_time }}</p>
  {% if entry.category %}<p>Labels: {% for cat in entry.category %}
   <a href="{{ tag_link }}{{ cat.term }}">{{ cat.term }}</a>
   {% if not forloop.last %}, {% endif %}
   {% endfor %}</p>{% endif %}<p><a href="{{ entry.my_link }}">More...</a></p>
   
{% endfor %}

And the second part handles the prev and next links


{% include 'bottom.html' %}

That's all for now. A working example is the gPowered.net site I'm putting up. All posts on there are getting pulled from this blog. I'm going to get into tags and comments next time, as well as javascript and php versions. Stay tuned!