it-swarm-ru.tech

Движок приложения по умолчанию 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')

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

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

Благодарю.

49
Saxon Druce

Как описано Ником в комментариях к ответу 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 не позволяет загружать шаблоны, которые находятся над каталогом исходного шаблона.

Обходной путь для этого описан здесь , но этот подход не мог работать для меня, поскольку он требует, чтобы шаблоны находились в подкаталоге шаблонов.

Решение этой проблемы состоит в том, чтобы настроить файл 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" %}

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

56
Saxon Druce

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

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

webapp_Django_version = '1.2'

Вот и все.

Больше нет необходимости в use_library().

17
Dave W. Smith

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

3
systempuntoout

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

2
Tyler Brandt