- Python 2.5 - later versions are not supported by GAE (http://www.python.org/ftp/python/2.5/python-2.5.msi)
- Google App Engine SDK for Python (http://code.google.com/intl/pl/appengine/downloads.html#Google_App_Engine_SDK_for_Python)
- Eclipse (http://www.eclipse.org/downloads/)
- Pydev - eclipse plugin for Python development (eclipse update site: http://pydev.org/updates)
Hello World project
Now, you can try to generate Hello World application using the Pydev's wizard. Create new project in eclipse - use "Pydev Google App Engine Project". Select Python version to 2.5 and configure interpreter to the one that you installed earlier. Next, you will have to specify path to Google App Engine SDK. On next page, set name for your application (the same as was registered on GAE account admin pages) and choose "Hello Webapp World" template. Within few seconds you should have your Hello World web app generated.
Run Google App Engine Launcher that was installed with SDK. If you are running it first time, configure paths to Python and SDK (Edit -> Preferences). Add your project to the Launcher:
Now, you should be able to run your application locally as well as deploy it to GAE. During deployment you will need to log into your GAE account.
More complex application
As usual, I created my test app as simple Book management application. It is not even CRUD as I had no time to develope update functionality. Application requires user to log in using Google Account before they enter the main page.
There, user will have links to other pages:
- Book list - when user will be able to display and remove books
- New book - page with form for adding new entries
- log out
Projects uses Google Webapp framework that is quite simple, but on the other hand you don't need anything more sophisticated for such simple app;)
Main application code and logic is in books.py:
import osIn this module we have main "controller" classes that cover all functionality. Classes are mapped to particular URL. Responsibility of each class is to perform business logic, prepare model and return template that will render the page:
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from models import Book
from google.appengine.ext.webapp.util import run_wsgi_app
class MainPage(webapp.RequestHandler):
def get(self):
user = users.get_current_user()
if user:
template_values = {
'user' : user.nickname(),
'logoutUrl' : users.create_login_url("/")
}
path = os.path.join(os.path.dirname(__file__)+"/templates", 'index.html')
self.response.out.write(template.render(path, template_values))
else:
self.redirect(users.create_login_url(self.request.uri))
class NewBookPage(webapp.RequestHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__)+"/templates", 'new.html')
self.response.out.write(template.render(path, {}))
class ListBooksPage(webapp.RequestHandler):
def get(self):
books = Book.all();
template_values = {
'books' : books,
}
path = os.path.join(os.path.dirname(__file__)+"/templates", 'list.html')
self.response.out.write(template.render(path, template_values))
class SaveBookPage(webapp.RequestHandler):
def post(self):
book = Book();
book.title = self.request.get('title')
book.author = self.request.get('author')
book.put()
self.redirect("/list")
class RemoveBookPage(webapp.RequestHandler):
def get(self):
book = Book.get(self.request.get('key'))
book.delete()
self.redirect("/list")
application = webapp.WSGIApplication(
[('/', MainPage),
('/list', ListBooksPage),
('/save', SaveBookPage),
('/remove', RemoveBookPage),
('/new', NewBookPage)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
- MainPage - prepares model for menu, returns index.html template
- NewBookPage - returns new.html template with form
- ListBooksPage - selects books from Google Datastore, puts them into model and returns list.html template
- SaveBookPage- saves book to datastore and redirects view to book list
- RemoveBookPage - removes book from datastore and redirects view to book list
Pages are implemented using Django templated mechanism that is included in SDK. We have a main template base.html that renders html page structure:
<html>All other templates are extending the main one.
<head>
<link type="text/css" rel="stylesheet" href="/style/main.css" />
</head>
<body>
{% block main %}
{% endblock %}
</body>
</html>
Code of index.html:
{% extends "base.html" %}list.html:
{% block main %}
Welcome {{ user }}!
<br/><br/>
Menu:<br/>
<a href="/list">Book list</a><br/>
<a href="/new">New book</a><br/>
<a href="{{ logoutUrl }}">Logout</a>
{% endblock %}
{% extends "base.html" %}new.html:
{% block main %}
<table>
<tr>
<th>Title</th>
<th>Author</th>
<th></th>
</tr>
{% for book in books %}
<tr>
<td>{{ book.title }}</td>
<td>{{ book.author }}</td>
<td><a href="/remove?key={{ book.key }}">remove</a></td>
</tr>
{% endfor %}
</table>
<br/>
<a href="/">Back</a>
{% endblock %}
{% extends "base.html" %}I used separete main.css file to define look (don't take it seriously hi hi) of the application:
{% block main %}
<form action="/save" method="POST">
<table>
<tr>
<td>Title:</td>
<td><input type="text" name="title"/></td>
</tr>
<tr>
<td>Author:</td>
<td><input type="text" name="author"/></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Add"></td>
</tr>
</table>
</form>
<br/>
<a href="/">Back</a>
{% endblock %}
body {In app.yaml file, we define that books.py module is responsible for handling all request to /* urls and that /style urls will be exposed as a static resource:
font-family: Verdana, Helvetica, sans-serif;
background-color: #DDDDDD;
}
application: python-test-maciekmData model is defined in models.py file:
version: 1
runtime: python
api_version: 1
handlers:
- url: /style
static_dir: style
- url: /.*
script: books.py
from google.appengine.ext import dbLet's see the result
class Book(db.Model):
title = db.StringProperty()
author = db.StringProperty()
Such application should be ready to get it started using Launcher and for deployment on GAE. When it starts, you should be able to see application pages in the browser - creating new book:
And the list:
Was it hard? To be honest I really think it was not. Personally, I think it was even easier for me to create GAE application in Python than in Java. In the future, I would be happy to try to use Django instead of Webapp framework and to compare them.