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).