Since app engine 1.4.2 was released, I am getting warnings like this in my production logs:
You are using the default Django
version (0.96). The default Django
version will change in an App Engine
release in the near future. Please
call use_library() to explicitly
select a Django version. For more
information see
http://code.google.com/appengine/docs/python/tools/libraries.html#Django
This occurs on every handler where I use a Django template – via the following:
from google.appengine.ext.webapp import template
I’d like to upgrade to 1.2, however the following links don’t seem very clear on exactly how to do this (or whether it works at all):
- http://code.google.com/appengine/docs/python/tools/libraries.html#Django
- http://code.google.com/p/googleappengine/issues/detail?id=1758
- http://code.google.com/p/googleappengine/issues/detail?id=4489
- http://www.mediacrafters.org/post/django11-on-appengine
The common thread is to insert this:
from google.appengine.dist import use_library
use_library('django', '1.2')
However, in what file(s) should this be inserted:
- Just in appengine_config.py?
- In every .py file which does
from google.appengine.ext.webapp import template? - In every .py file in the project?
- In 1 and (2 or 3) above, and also add
import appengine_configto those files? - In 3 or 4, and also add wrappers around built-in functions like appstats, remote api, datastore admin, etc?
- Something else?
Thanks.
As described by Nick in the comments of systempuntoout’s answer, I inserted this
use_library()code from here in every handler that imports django (either directly or viagoogle.appengine.ext.webapp.templateor even justdjango.utils.simplejson):As suggested by Nick, this was made easier by first refactoring to minimise the number of handlers referenced by app.yaml (ie, closer to scenario 1 described here).
However, I have the appstats builtin configured, and if I first went to /_ah/appstats after an upload, then I would get this error:
I was able to fix this by also including the
use_library()code inappengine_config.py.I noticed that by inserting a call to
use_library()inappengine_config.py, then it was no longer necessary in all of my handlers. In particular the ones which importgoogle.appengine.ext.webapp.templatedon’t need it, because importingwebapp.templateloadsappengine_config.py. The appstats UI importswebapp.template, which is why this fixed that problem.However, I had some handlers (eg json services) which don’t import
webapp.template, but do importdjango.utils.simplejson. These handlers still require a direct call touse_library(). Otherwise, if those handlers are called first on a new instance, theUnacceptableVersionErroroccurs. Although I am usingappengine_config.pyto configure appstats, meaningappengine_config.pygets called to instrument all requests, it gets called too late in the page lifecycle to properly configure the correct version of Django.This all appeared to work okay at first, but then I discovered a backwards incompatibility between the new Django 1.2 and the old Django 0.96 which I’d been using. My project structure is like this:
With Django 0.96, having the following in page_admin.html worked fine:
With Django 1.2, I got this error:
The change in Django 1.2 seems to be that by default, Django doesn’t allow loading templates which are above the original template’s directory.
A workaround for this is described here, but this approach couldn’t work for me, as it requires the templates to be in a templates subdirectory.
The solution to this is to set up a
settings.pyfile, set theTEMPLATE_DIRSsetting to the project root directory, and then change theextendstag to just reference"page_base.html", as described here. However, I ran into two problems trying to do this.I was using the recommended code to render my template, ie:
The first problem is that
template.render()overrides theTEMPLATE_DIRSsetting, to set it to the directory of the template being rendered. The solution to this is the following code:One downside of this approach though is that
template.render()caches the compiled templates, whereas this code doesn’t (although that wouldn’t be hard to add).To configure the
TEMPLATE_DIRSsetting, I added asettings.pyto my project:And then in all of my handlers, before the
use_library()code, I set theDJANGO_SETTINGS_MODULEas described here:The second problem was that this didn’t work – the settings file wasn’t getting loaded, and so the
TEMPLATE_DIRSwas empty.Django settings are loaded from the specified
settings.pylazily, the first time they are accessed. The problem is that importingwebapp.templatecallsdjango.conf.settings.configure()to attempt to set up some settings. Therefore ifwebapp.templateis imported before any settings are accessed, thensettings.pyis never loaded (as the settings accessor finds that settings already exist, and doesn’t attempt to load any more).The solution to this is to force an access to the settings, to load the
settings.py, beforewebapp.templateis imported. Then whenwebapp.templateis later imported, its call todjango.conf.settings.configure()is ignored. I therefore changed the Django version setup code in all of my handlers (andappengine_config.py) to the following:In practise, I actually put all of the above code in a file called
setup_django_version.py, and then import that from all of my handlers, rather than duplicating these 6 lines of code everywhere.I then updated my
page_admin.htmltemplate to include this (ie specifypage_base.htmlrelative to theTEMPLATE_DIRSsetting):And that fixed the problem with rendering the admin page.