Posting to the Twitter API on an admin change

Django    2009-04-07

For context, I've been working on a project that involves submitted messages going through a manual review process - once they've been approved in the admin, each message should be posted to Twitter. My Twitter API script is over here, for reference.

I had originally thought I'd set up a cron job to run the posting script, and I still might go back to that if the manual review from the admin starts to take too much time. Doug Hellman suggested using signals, but after some consideration I realized that Django signals would probably be overkill - it's a little disappointing because I've never actually gotten signals working in a project. I need a use case to make me figure it out, and I thought this would be it.

Instead I was browsing some old code and realized that, oh yeah, I can put a save method in my admin class ... honestly, I'm embarrassed that I didn't think of it first - it's a no-brainer.

I just wrapped all the script code in a method:

    #!/usr/bin/python
    
    import MySQLdb as Database
    import base64, urllib, urllib2
    
    def main():
        db = Database.connect("myhost", "myuser", "mypasswd", "mydbname")
        cursor = db.cursor(Database.cursors.DictCursor)
    
        sql = """SELECT * FROM twitter_message WHERE approved=1 AND posted=0"""
        cursor.execute(sql)
        data = cursor.fetchall()
    
        username = "twitter_username"
        password = "twitter_password"
    
        for record in data:
            message = record["message"]
            message = message.replace(',', '')
            post_data = {'status': message}
    
            request = urllib2.Request('http://twitter.com/statuses/update.json')
            request.headers['Authorization'] = 'Basic %s' % ( base64.b64encode(username + ':' + password),)
            request.data = urllib.urlencode({'status': message})
            response = urllib2.urlopen(request) # The Response
    
            """ the most painful part is hacking up the response to get at the status id """
            a = response.read()
            b = a.split(',') ## convert the whole thing to a list
            c = b[30] ## hope the id is always the 30th item in the list
            d = INT(c[5:]) ## strip off first part of string, leave behind the number
          
            if response.code == 200 and type(d) == int:
                record_id = record["id"]
                sql = """UPDATE twitter_message posted=1, post_date=NOW(), status_id=%s WHERE id=%s""" %(d, record_id)
                cursor.execute(sql)
    
        cursor.close()
        db.close()
    
    if __name__ == "__main__":
        main()
    

Then imported it as a module and called it from the relevant admin.py:

    import twitterpost
    
    class TweetAdmin(admin.ModelAdmin):
        def save_model(self, request, obj, form, change):
            obj.save()
            if obj.approved: twitterpost.main()
        list_filter = ('approved',)
    

Note that the script is called after the obj.save() - the script only acts on records that have already been marked 'approved'.

That's it. Three extra lines of code (six if you count what I added to the script).