Ответ 1
Как описано Nick в комментариях ответа systempuntoout, я вставил этот use_library()
код отсюда в каждом обработчике, который импортирует django ( либо напрямую, либо через google.appengine.ext.webapp.template
или даже просто django.utils.simplejson
):
from google.appengine.dist import use_library
use_library('django', '1.2')
Как было предложено Ником, это было упрощено с помощью первого рефакторинга, чтобы свести к минимуму количество обработчиков, на которые ссылается app.yaml(т.е. ближе к сценарию 1, описанному здесь).
Тем не менее, у меня настроено настроение appstats, и если я сначала отправился в /_ah/appstats после загрузки, я бы получил эту ошибку:
< 'google.appengine.dist._library.UnacceptableVersionError' > : django 1.2 был запрошен, но 0.96.4. Уже не используется
Я смог исправить это, также включив код use_library()
в appengine_config.py
.
Я заметил, что, вставив вызов use_library()
в appengine_config.py
, он больше не нужен во всех моих обработчиках. В частности те, которые импортируют google.appengine.ext.webapp.template
, не нуждаются в нем, потому что импорт webapp.template
загружает appengine_config.py
. Пользовательский интерфейс appstats импортирует 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 не позволяет загружать шаблоны, которые находятся выше исходного каталога шаблонов.
Обходной путь для этого описан здесь, но этот подход не мог работать для меня, так как он требует, чтобы шаблоны были в templates.
Решением этого является установка файла 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
, чтобы установить его в каталог отображаемого шаблона. Решением этого является следующий код:
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
как описано здесь:
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
Вторая проблема заключалась в том, что это не сработало - файл настроек не загружался, поэтому TEMPLATE_DIRS
был пуст.
Настройки Django загружаются из указанного settings.py
лениво, при первом обращении к ним. Проблема заключается в том, что импорт webapp.template
вызывает django.conf.settings.configure()
, чтобы попытаться настроить некоторые параметры. Поэтому, если webapp.template
импортируется до того, как будут доступны какие-либо настройки, тогда settings.py
никогда не будет загружаться (поскольку аксессуар настроек обнаруживает, что настройки уже существуют и больше не пытается загружаться).
Решение этого - принудительно получить доступ к настройкам, загрузить settings.py
, прежде чем webapp.template
будет импортировано. Затем, когда webapp.template
позже импортируется, его вызов django.conf.settings.configure()
игнорируется. Поэтому я изменил код установки версии Django во всех моих обработчиках (и appengine_config.py
) на следующее:
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" %}
И это устранило проблему с рендерингом страницы администратора.