应用引擎默认的Django版本更改

由于应用程序引擎1.4.2发布,我在我的生产日志中得到这样的警告:

您正在使用默认的Django版本(0.96)。 在不久的将来,默认的Django版本将在App Engine版本中发生变化。 请调用use_library()来显式select一个Django版本。 有关详情,请参阅http://code.google.com/appengine/docs/python/tools/libraries.html#Django

这发生在我使用Django模板的每个处理程序上 – 通过以下方式:

from google.appengine.ext.webapp import template 

我想升级到1.2,但是下面的链接到底是怎么做的(或者它是否工作)似乎并不是很清楚:

  • 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

共同的线索是插入这个:

 from google.appengine.dist import use_library use_library('django', '1.2') 

但是,应该在什么文件中插入:

  1. 只是在appengine_config.py?
  2. from google.appengine.ext.webapp import template每个.py文件中?
  3. 在项目中的每个.py文件中?
  4. 在上面的1和(2或3)中,还将import appengine_config添加到这些文件中?
  5. 在3或4,还添加了内置函数,如appstats,远程API,数据存储pipe理员等的包装?
  6. 别的东西?

谢谢。

正如在systempuntoout的回答中,Nick所描述的那样,我从这里插入了这个use_library()代码到每个导入django的处理程序(直接或通过google.appengine.ext.webapp.template或者甚至只是django.utils.simplejson )中:

 from google.appengine.dist import use_library use_library('django', '1.2') 

正如Nick所build议的那样,通过第一次重构,使得app.yaml所引用的处理程序的数量最小化(即,更接近这里描述的场景1 ),这变得更容易。

不过,我已经configuration了内置的appstats,如果我在上传之后首先去了/ _ah / appstats,那么我会得到这个错误:

<'google.appengine.dist._library.UnacceptableVersionError'>:请求了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 。 尽pipe我使用appengine_config.py来configurationappstats,但是appengine_config.py被调用来处理所有的请求,在页面生命周期中被调用得太晚,无法正确configuration正确版本的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不允许加载模板的原始模板的目录之上。

这里描述了一个解决方法,但是这种方法对我不起作用,因为它要求模板在模板子目录中。

解决方法是设置settings.py文件,将TEMPLATE_DIRS设置为项目根目录,然后将extends标记更改为仅引用"page_base.html" ,如此处所述 。 但是,我遇到了两个问题,试图做到这一点。

我正在使用推荐的代码来呈现我的模板,即:

 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设置,将其设置为要呈现的模板的目录。 对此的解决scheme是以下代码:

 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()caching了编译好的模板,而这段代码却没有(尽pipe这样做不难)。

要configurationTEMPLATE_DIRS设置,我添加了一个settings.py到我的项目中:

 PROJECT_ROOT = os.path.dirname(__file__) TEMPLATE_DIRS = (PROJECT_ROOT,) 

然后在我的所有处理程序中,在use_library()代码之前,我设置了DJANGO_SETTINGS_MODULE 如下所述 :

 import os os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' 

第二个问题是,这不起作用 – 设置文件没有得到加载,所以TEMPLATE_DIRS是空的。

Django设置是从指定的settings.py中第一次被访问时被加载的。 问题是导入webapp.template调用django.conf.settings.configure()尝试设置一些设置。 因此,如果在访问任何设置之前导入了webapp.template ,那么settings.py永远不会被加载(因为设置访问器发现设置已经存在,并且不会再尝试加载)。

解决scheme是强制访问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模板以包含此(即指定page_base.html相对于TEMPLATE_DIRS设置):

 {% extends "page_base.html" %} 

这解决了渲染pipe理页面的问题。

从GAE 1.5.0开始,有很多简单的,虽然暂时没有详细logging的方法,可以指定要使用的Django模板的版本。

appengine_config.py ,包含该行

 webapp_django_version = '1.2' 

而已。

不再需要use_library()

根据您正确链接的文档 ,您应该在main.py脚本处理程序的开头添加此函数。

有一件事我想提到, 文档没有明确说明:如果你使用google.appengine.ext.deferred并且在你的main.pymain.py ,那么当执行延迟任务时,它不会加载main.py如果你不幸有一个推迟的任务作为你对实例的第一个请求,那么它就会执行这个实例(当你的main.py试图在稍后的请求中调用use_library时,它会抛出UnacceptableVersionError )。 我想如果你添加use_libaryappengine_config.py它也可以和deferred工作,但是我们最终切换到了常规任务队列(通过main.py路由的处理程序)以避免这个问题。