Wednesday, September 15, 2010

Using OAuth with Spreadsheets API on Django/AppEngine

In a previous blog post, I showed how to import a published spreadsheet feed into an App Engine datastore by just grabbing the JSON. For another project I'm working on, I need to be able to import a *private* spreadsheet into an App Engine datastore. Because of the need to authenticate the user (via the multiple steps of the ever-so-elegant OAuth dance), this importing requires much more finagling.

With the help of my trusty colleague Vic Fryzel, I've put together a set of Django views that use the Python GData Client Library and should run on both App Engine Django, and with some modification for token storage, other Django stacks. I'll walkthrough the views here.

There are four URL handlers required, two for token requests, one for actually importing the spreadsheet, and one to manage the flow:

In this first step of the OAuth dance, the app requests an oauth token for the specified scope (Spreadsheets), key/secret (anonymous, as I haven't registered my app), and a callback URL to my app. It saves that token to the App Engine datastore using a convenience function in the client library. Then it redirects the user to the authorization URL for that token, and the user is presented with the "Grant access" screen.

When the user returns from the authorization screen to the callback handler, the app retrieves the original token, asks Google to upgrade that to an access token, and saves the access token to the App Engine datastore again.

The user is then redirected to the main page, and since it sees that there is now an access token for the user, it shows the user an input box for providing a spreadsheets URL. When it knows the spreadsheets URL, it retrieves the list feed for that spreadsheet and saves each row as an entity in the datastore.

For simplicity's sake, this sample shows the simplest possible import. In my actual project, I am also creating an entity that represents the entire spreadsheet, and the entity for each row refer to that entity. In addition, I have code to convert from the spreadsheets strings to other model types like dates.

Hopefully this project can serve as a basis for other developers using spreadsheets as an import source for their apps. Enjoy!