自从app engine 1.4.2发布以来,我在生产日志中收到类似警告:
您正在使用默认的Django 版本(0.96)。默认的Django 版本将在App Engine中更改 在不久的将来发布。请 调用use_library()来显式地 选择一个Django版本。更多 信息见 http://code.google.com/appengine/docs/python/tools/libraries.html#Django
这发生在我使用Django模板的每个处理程序上 - 通过以下内容:
from google.appengine.ext.webapp import template
我想升级到1.2,但以下链接似乎并不清楚如何做到这一点(或者它是否有效):
共同点是插入:
from google.appengine.dist import use_library
use_library('django', '1.2')
但是,应插入哪个文件:
from google.appengine.ext.webapp import template
?。import appengine_config
添加到这些文件中?感谢。
答案 0 :(得分:56)
正如Nick在systempuntoout的回答中所描述的那样,我在每个导入django的处理程序中插入了use_library()
代码from here(直接或通过google.appengine.ext.webapp.template
甚至只是{{1} }}):
django.utils.simplejson
正如尼克所建议的那样,通过首次重构来减少app.yaml引用的处理程序数量(即接近scenario 1 described here),这一过程变得更容易了。
但是,我已经内置配置appstats,如果我在上传后第一次去/ _ah / appstats,那么我会收到此错误:
< 'google.appengine.dist._library.UnacceptableVersionError' 计算值: 请求django 1.2,但是 0.96.4。尚未使用
我能够通过在from google.appengine.dist import use_library
use_library('django', '1.2')
中添加use_library()
代码来解决此问题。
我注意到,通过在appengine_config.py
中插入对use_library()
的调用,我的所有处理程序都不再需要了。特别是导入appengine_config.py
的人不需要它,因为导入google.appengine.ext.webapp.template
会加载webapp.template
。 appstats UI导入appengine_config.py
,这就是解决此问题的原因。
但是,我有一些处理程序(例如json服务)不导入webapp.template
,但导入webapp.template
。这些处理程序仍需要直接调用django.utils.simplejson
。否则,如果在新实例上首先调用这些处理程序,则会发生use_library()
。虽然我使用UnacceptableVersionError
来配置appstats,意味着appengine_config.py
被调用以检测所有请求,但在页面生命周期中调用它太晚才能正确配置Django的正确版本。
这一切看起来一切正常,但后来我发现新Django 1.2和我一直在使用的旧Django 0.96之间的向后不兼容。我的项目结构是这样的:
appengine_config.py
使用Django 0.96,在page_admin.html中有以下内容正常工作:
root
+- admin
| +- page_admin.html
+- page_base.html
使用Django 1.2,我收到了这个错误:
TemplateDoesNotExist:../ page_base.html
Django 1.2的变化似乎是默认情况下,Django不允许加载原始模板目录之上的模板。
对此进行了解决方法here,但这种方法对我来说无效,因为它需要模板位于模板子目录中。
解决方案是设置{% extends "../page_base.html" %}
文件,将settings.py
设置设置为项目根目录,然后将TEMPLATE_DIRS
标记更改为仅引用{{1} },described here。但是,我试图做到这两个问题。
我使用recommended code渲染我的模板,即:
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
缓存已编译的模板,而这段代码没有(虽然这不会很难添加)。
要配置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,)
as described here:
use_library()
第二个问题是这不起作用 - 设置文件没有加载,因此DJANGO_SETTINGS_MODULE
为空。
Django设置是在第一次访问时从懒惰的指定import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
加载的。问题是导入TEMPLATE_DIRS
调用settings.py
以尝试设置某些设置。因此,如果在访问任何设置之前导入webapp.template
,则永远不会加载django.conf.settings.configure()
(因为设置访问者发现设置已存在,并且不再尝试加载)。
解决方法是在导入webapp.template
之前强制访问设置,加载settings.py
。然后,稍后导入settings.py
时,将忽略对webapp.template
的调用。因此,我将所有处理程序(和webapp.template
)中的Django版本设置代码更改为以下内容:
django.conf.settings.configure()
实际上,我实际上将所有上述代码放在一个名为appengine_config.py
的文件中,然后从我的所有处理程序中导入,而不是在任何地方复制这6行代码。
然后我更新了我的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
设置指定page_admin.html
):
page_base.html
这解决了呈现管理页面的问题。
答案 1 :(得分:17)
从GAE 1.5.0开始,指定您想要使用哪个版本的Django模板的方法要简单得多,但却暂时未充分记录。
在appengine_config.py
中,加上
webapp_django_version = '1.2'
就是这样。
不再需要use_library()
。
答案 2 :(得分:3)
根据您正确链接的documentation,您应该只在main.py
脚本处理程序的开头添加此函数。
答案 3 :(得分:2)
有一件事我想提及documentation并不明确:如果您在use_library
中使用google.appengine.ext.deferred
并拥有main.py
,那么延迟任务已执行它将不会加载main.py
如果您不幸将延迟任务作为对实例的第一个请求,它将使实例生效(导致它抛出{ {1}} UnacceptableVersionError
尝试在以后的请求中致电main.py
时{1}}我认为如果您将use_library
添加到appengine_config.py
,它也可以与use_libary
一起使用,但我们最终切换到常规任务队列(处理程序通过deferred
路由)到避免这个问题。