正如尼克在 systempuntoout 回答的 cmets 中所述,我在每个导入 django 的处理程序中插入了这个 use_library() 代码 from here(直接或通过 google.appengine.ext.webapp.template 甚至只是 django.utils.simplejson):
from google.appengine.dist import use_library
use_library('django', '1.2')
正如 Nick 所建议的,通过首先重构以最小化 app.yaml 引用的处理程序的数量(即更接近 scenario 1 described here),这变得更容易了。
但是,我已经配置了内置的 appstats,如果我在上传后第一次去 /_ah/appstats,那么我会收到这个错误:
:
要求 django 1.2,但是
0.96.4.None 已在使用中
我还可以通过在appengine_config.py 中包含use_library() 代码来解决此问题。
我注意到通过在appengine_config.py 中插入对use_library() 的调用,我的所有处理程序都不再需要它了。特别是那些导入google.appengine.ext.webapp.template 的不需要它,因为导入webapp.template 会加载appengine_config.py。 appstats UI 导入 webapp.template,这就是解决该问题的原因。
但是,我有一些处理程序(例如 json 服务)不导入 webapp.template,而是导入 django.utils.simplejson。这些处理程序仍然需要直接调用use_library()。否则,如果在新实例上首先调用这些处理程序,则会出现 UnacceptableVersionError。虽然我使用 appengine_config.py 来配置 appstats,这意味着调用 appengine_config.py 来检测所有请求,但在页面生命周期中调用它为时已晚,无法正确配置正确的 Django 版本。
一开始这一切似乎都可以正常工作,但后来我发现新的 Django 1.2 和我一直在使用的旧 Django 0.96 之间存在向后不兼容的问题。我的项目结构是这样的:
root
+- admin
| +- page_admin.html
+- page_base.html
使用 Django 0.96,在 page_admin.html 中有以下内容可以正常工作:
{% extends "../page_base.html" %}
使用 Django 1.2,我收到此错误:
TemplateDoesNotExist: ../page_base.html
Django 1.2 的变化似乎是默认情况下,Django 不允许加载原始模板目录之上的模板。
here 描述了一种解决方法,但这种方法对我不起作用,因为它要求模板位于模板子目录中。
解决方法是建立一个settings.py文件,将TEMPLATE_DIRS设置为项目根目录,然后将extends标签改为只引用"page_base.html",为described here。但是,我在尝试这样做时遇到了两个问题。
我使用recommended code 来渲染我的模板,即:
template_values = { ... }
path = os.path.join(os.path.dirname(__file__), 'page_admin.html')
self.response.out.write(template.render(path, template_values))
第一个问题是template.render() 覆盖了TEMPLATE_DIRS 设置,将其设置为正在渲染的模板的目录。解决方法如下:
template_values = { ... }
path = os.path.join(os.path.dirname(__file__), 'page_admin.html')
template_file = open(path)
compiled_template = template.Template(template_file.read())
template_file.close()
self.response.out.write(compiled_template.render(template.Context(template_values)))
这种方法的一个缺点是 template.render() 缓存已编译的模板,而此代码没有(尽管添加起来并不难)。
为了配置TEMPLATE_DIRS 设置,我在我的项目中添加了settings.py:
PROJECT_ROOT = os.path.dirname(__file__)
TEMPLATE_DIRS = (PROJECT_ROOT,)
然后在我所有的处理程序中,在 use_library() 代码之前,我设置了 DJANGO_SETTINGS_MODULE as described here:
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
第二个问题是这不起作用 - 设置文件没有被加载,因此 TEMPLATE_DIRS 是空的。
Django 设置从指定的settings.py 延迟加载,第一次访问它们。问题是导入webapp.template 会调用django.conf.settings.configure() 来尝试设置一些设置。因此,如果在访问任何设置之前导入了 webapp.template,则永远不会加载 settings.py(因为设置访问器发现设置已经存在,并且不再尝试加载)。
解决方案是在导入webapp.template 之前强制访问设置,加载settings.py。然后当稍后导入webapp.template 时,它对django.conf.settings.configure() 的调用将被忽略。因此,我将所有处理程序(和appengine_config.py)中的 Django 版本设置代码更改为以下内容:
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from google.appengine.dist import use_library
use_library('django', '1.2')
from django.conf import settings
_ = settings.TEMPLATE_DIRS
在实践中,我实际上将上述所有代码放在一个名为 setup_django_version.py 的文件中,然后从我的所有处理程序中导入它,而不是到处复制这 6 行代码。
然后我更新了我的page_admin.html 模板以包含这个(即相对于TEMPLATE_DIRS 设置指定page_base.html):
{% extends "page_base.html" %}
这解决了呈现管理页面的问题。