Django on Google App Engine in 13 simple steps:
April 8, 2008 – 6:48 pmIn this tutorial I will show you how to get a simple datastore-backed Django application up and running on the Google App Engine. I will assume that you are somewhat familiar with Django.
Update 1: You can download the full set of files from here. Make sure to fix the sys.path in main.py.
Update 2: There is now a Turkish translation of this tutorial, courtesy of Türker Sezer.
Update 3: Now in Russian as well.
Step 1: Register an app name and install the development kit per the instructions.
Step 2: Create a directory for your application—for this tutorial my application is called mashname:
-
tmp$ mkdir mashname
-
tmp$ cd mashname
Step 3: Add a file called main.py to your new directory:
-
import os, sys
-
os.environ["DJANGO_SETTINGS_MODULE"] = "mashname.settings"
-
sys.path.append("/home/brox/tmp/mashname")
-
-
# Google App Engine imports.
-
from google.appengine.ext.webapp import util
-
-
# Force Django to reload its settings.
-
from django.conf import settings
-
settings._target = None
-
-
import django.core.handlers.wsgi
-
import django.core.signals
-
import django.db
-
import django.dispatch.dispatcher
-
-
# Log errors.
-
#django.dispatch.dispatcher.connect(
-
# log_exception, django.core.signals.got_request_exception)
-
-
# Unregister the rollback event handler.
-
django.dispatch.dispatcher.disconnect(
-
django.db._rollback_on_exception,
-
django.core.signals.got_request_exception)
-
-
def main():
-
# Create a Django application for WSGI.
-
application = django.core.handlers.wsgi.WSGIHandler()
-
-
# Run the WSGI CGI handler with that application.
-
util.run_wsgi_app(application)
-
-
if __name__ == "__main__":
-
main()
This is basically the same file as suggested here, except I had to set the Python path to be able to test locally. I also had to set the DJANGO_SETTINGS_MODULE—this might not be necessary when running on the App Engine. I had to disable the error logging which I was not able to get working.
Step 4: Add a file called app.yaml to the same directory:
-
application: mashname
-
version: 1
-
runtime: python
-
api_version: 1
-
-
handlers:
-
- url: /.*
-
script: main.py
Make sure to get the application name right.
Step 5: From your mashname directory, create a new Django project:
-
tmp/mashname$ django-admin.py startproject mashname
(I’m assuming that your current Django setup is working as it should.)
Step 6: You should now be able to test your application:
-
tmp/mashname$ cd ..
-
tmp$ dev_appserver.py mashname
-
INFO 2008-04-08 19:08:10,023 appcfg.py] Checking for updates to the SDK.
-
INFO 2008-04-08 19:08:10,384 appcfg.py] The SDK is up to date.
-
INFO 2008-04-08 19:08:10,404 dev_appserver_main.py] Running application mash
-
name on port 8080: http://localhost:8080
Point your browser towards http://127.0.0.1:8080/ and you should get the standard Django It worked! message.
Step 7: Create a Django app within the project:
-
tmp$ cd mashname
-
tmp/mashname$ python mashname/manage.py startapp main
Step 8: Now it is time to add a model. We will be creating a simple application that logs all visitors to the data store and displays their IP address and time of visit. Edit ~/mashname/mashname/main/models.py so that it looks like this:
-
from google.appengine.ext import db
-
-
class Visitor(db.Model):
-
ip = db.StringProperty()
-
added_on = db.DateTimeProperty(auto_now_add=True)
There is no need to sync the database since we are not using regular Django models.
Step 9: Now we create a view that is responsible for both adding data to the Visitor model and showing the previous visitors. Edit views.py (in the same directory as models.py) so that it does what we want:
-
from django.http import HttpResponse
-
-
from mashname.main.models import Visitor
-
-
def main(request):
-
visitor = Visitor()
-
visitor.ip = request.META["REMOTE_ADDR"]
-
visitor.put()
-
-
result = ""
-
visitors = Visitor.all()
-
visitors.order("-added_on")
-
-
for visitor in visitors:
-
result += visitor.ip + u" visited on " + unicode(visitor.added_on) + u""
-
-
return HttpResponse(result)
Step 10: Finally, make your urls.py point towards the view:
-
from django.conf.urls.defaults import *
-
-
urlpatterns = patterns("",
-
(r"^$", "mashname.main.views.main"),
-
)
Step 11: Test your application (as in step 6) and everything should hopefully work. For each page reload a new entry is added to the Visitor model and shown in the view.
Step 12: Upload your application to the Google App Engine:
-
tmp$ appcfg.py update mashname
For the first upload you will have to provide the mail address and password for your Google account.
Step 13: Enjoy! To view the final results, go to http://mashname.appspot.com/.
17 Responses to “Django on Google App Engine in 13 simple steps: ”
I opened a bug about the logging issue at http://code.google.com/p/googleappengine/issues/detail?id=16
The docs have been updated to fix it, but line setting the DJANGO_SETTINGS_MODULE is still not complete.
By Jay on Apr 8, 2008
Been having some trouble myself with some of the restrictions they’ve placed on it… but great writeup, i think i might take a django route so that i can at least get something up there to test the service out.
Thanks,
Brent
By Brent on Apr 8, 2008
Thanks for the intro. Django is certainly an interesting-looking environment to program in. (I’ve got up through Ch. 4 of the Django Book this evening).
You should fix your Wordpress theme. It make the quotes slanty, which makes them interpreted as different characters than the standard single quote. I copied the add path line from your code and got a syntax error because of it.
Thanks again for documenting Google’s hacked-up version of Django better than they do. =)
By Brenton on Apr 9, 2008
@Brenton: Thanks for telling me about the single quote problem. I have replaced them with double quotes.
By Thomas Brox Røst on Apr 9, 2008
Hi Thomas,
http://mashname.appspot.com/ is not accessible. IS there someplace from where I can pull up your whole code and then use this? I am able to use things which I have developed from my local dev server, but not from the Google’s server. I get weird 500 errors.
PS. You might like to read this, http://www.42topics.com/dumps/appengine/doc.html, and we might share ideas.
By Shabda on Apr 9, 2008
@Shabda: It should be accessible most of time—try again. I get the occassional error message in the App Engine log file:
This request used a high amount of CPU, and was roughly 2.2 times over the average request CPU limit. High CPU requests have a small quota, and if you exceed this quota, your app will be temporarily disabled.
Don’t really know why, though. I added a link to the full set of files at the top of the page.
By Thomas Brox Røst on Apr 9, 2008
Hi Thomas,
You might find this link to be of interest http://www.42topics.com/dumps/django/docs.html
By Shabda on Apr 11, 2008
Hi,
this is helping me a great deal to get started. Now I’m using a template file and I’m trying to add a CSS file to it, do you know which file do I have to modify to let Django find my CSS file?
Thanks in advance
By Phuong on Apr 20, 2008
@Phuong: I just wrote a new tutorial that shows you how to serve templates and static files. Have a look at it here.
By Thomas Brox Røst on Apr 20, 2008
Thanks for the excellent article Thomas.
I am encountering the following error with step 6 (any thoughts on how to get past this?):
ERROR 2008-04-27 06:17:40,287 dev_appserver.py] Encountered error loading module “main”: :
ERROR 2008-04-27 06:17:40,287 dev_appserver.py] Parent package initialization files are present, but must be broken
ERROR 2008-04-27 06:17:40,289 dev_appserver.py] Exception encountered handling request
Traceback (most recent call last):
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 2247, in _HandleRequest
base_env_dict=env_dict)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 334, in Dispatch
base_env_dict=base_env_dict)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1743, in Dispatch
self._module_dict)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1654, in ExecuteCGI
reset_modules = exec_script(handler_path, cgi_path, hook)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1550, in ExecuteOrImportScript
handler_path, cgi_path, import_hook)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1479, in LoadTargetModule
module_code = import_hook.get_code(module_fullname)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 806, in decorate
return func(self, *args, **kwargs)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1350, in get_code
full_path, search_path, submodule = self.GetModuleInfo(fullname)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 806, in decorate
return func(self, *args, **kwargs)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1305, in GetModuleInfo
source_file, pathname, description = self.FindModuleRestricted(submodule, fullname, search_path)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 806, in decorate
return func(self, *args, **kwargs)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1136, in FindModuleRestricted
raise CouldNotFindModuleError()
CouldNotFindModuleError
INFO 2008-04-27 06:17:40,290 dev_appserver.py] “GET / HTTP/1.1″ 500 -
ERROR 2008-04-27 06:17:40,351 dev_appserver.py] Encountered error loading module “main”: :
ERROR 2008-04-27 06:17:40,351 dev_appserver.py] Parent package initialization files are present, but must be broken
ERROR 2008-04-27 06:17:40,353 dev_appserver.py] Exception encountered handling request
Traceback (most recent call last):
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 2247, in _HandleRequest
base_env_dict=env_dict)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 334, in Dispatch
base_env_dict=base_env_dict)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1743, in Dispatch
self._module_dict)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1654, in ExecuteCGI
reset_modules = exec_script(handler_path, cgi_path, hook)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1550, in ExecuteOrImportScript
handler_path, cgi_path, import_hook)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1479, in LoadTargetModule
module_code = import_hook.get_code(module_fullname)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 806, in decorate
return func(self, *args, **kwargs)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1350, in get_code
full_path, search_path, submodule = self.GetModuleInfo(fullname)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 806, in decorate
return func(self, *args, **kwargs)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1305, in GetModuleInfo
source_file, pathname, description = self.FindModuleRestricted(submodule, fullname, search_path)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 806, in decorate
return func(self, *args, **kwargs)
File “/usr/local/google_appengine/google/appengine/tools/dev_appserver.py”, line 1136, in FindModuleRestricted
raise CouldNotFindModuleError()
CouldNotFindModuleError
INFO 2008-04-27 06:17:40,354 dev_appserver.py] “GET /favicon.ico HTTP/1.1″ 500 -
By Dondi on Apr 27, 2008
@Dondi: I haven’t seen that particular error message before. It looks like there is something wrong with one of your files (”Parent package initialization files are present, but must be broken”).
Check that the Django application you created in the previous step (”main”) contains all the necessary files (”__init__.py”, “models.py” and “views.py”). Then verify that the Django project directory has the files “__init__.py”, “manage.py”, “settings.py” and “urls.py”.
Finally, make sure that there are no errors in the App Engine configuration files (”main.py” and “app.yaml”). You might have the wrong path or project name.
If you downloaded the zip file onto a Linux box: Try running the dos2unix utility on the entire directory. I wrote the tutorial on a Windows machine so there might be some line feed/carriage return encoding weirdness.
By Thomas Brox Røst on Apr 27, 2008
Thank you for this great tutorial, Thomas!
I’m also done Russian translation of it at my blog:
http://konkursof.blogspot.com/2008/05/django-google-app-engine-12.html
By V.Sergeyev on May 11, 2008