Подтвердить что ты не робот

Изменение версии Django в драйвере приложения по умолчанию

Так как был выпущен движок 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')

Однако, в каком файле (файлах) это должно быть вставлено:

  • Просто в appengine_config.py?
  • В каждом .py файле, который делает from google.appengine.ext.webapp import template?
  • В каждом файле .py в проекте?
  • В 1 и (2 или 3) выше, а также добавить import appengine_config в эти файлы?
  • В 3 или 4, а также добавить оболочки вокруг встроенных функций, таких как appstats, удаленный api, datastore admin и т.д.
  • Что-то еще?

Спасибо.

4b9b3361

Ответ 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" %}

И это устранило проблему с рендерингом страницы администратора.

Ответ 2

Как и в случае с GAE 1.5.0, гораздо проще, хотя и надолго задокументировано, указать, какую версию шаблонов Django вы хотите использовать.

В appengine_config.py включить строку

webapp_django_version = '1.2'

Что это.

Больше не нужно use_library().

Ответ 3

В соответствии с документацией, которую вы правильно связываете, вы должны просто добавить эту функцию в начало вашего обработчика main.py script.

Ответ 4

Хочу отметить, что документация не уточняет: если вы используете google.appengine.ext.deferred и use_library в main.py, а затем, когда выполняется отложенная задача, НЕ загружается main.py, и если вам не повезло, чтобы иметь отложенную задачу как ваш первый запрос к экземпляру, он будет возбуждать экземпляр (заставляя его бросать UnacceptableVersionError, когда ваш main.py пытается вызвать use_library для более позднего запроса). Я думаю, что если вы добавите use_libary в appengine_config.py, он будет работать и с deferred, но мы перешли на обычные очереди задач (обработчики ARE маршрутизируются через main.py), чтобы избежать этой проблемы.