Чтобы начать использовать App Engine понадобятся:
- Интерпретатор Python 2
- Google App Engine SDK for Python
Python 3 на данный момент не поддерживается App Engine. Минимально необходимая версия среды — 2.5, но для новых проектов Google рекомендует сразу использовать версию 2.7. У меня установлены Python 2.7.2 и SDK 1.7.0 на Windows 7.
Настройка SDK сводится к указанию пути к исполняемому файлу Python. Запускаем Google App Engine Launcher, идём в меню Edit -> Preferences, в строке Python Path прописываем путь к файлу python.exe (например: C:Python27python.exe
).
Как верно заметил igrishaev в комментарии к первой части, App Engine SDK — это набор скриптов. Launcher — всего лишь графическая оболочка для быстрого доступа к часто используемым операциям: запуск/остановка dev-сервера, просмотр логов, открытие консоли SDK, развёртывание приложения и другие. Сами файлы .py-скриптов лежат в папке с установленной SDK и могут быть запущены непосредственно из командной строки или, например, использованы в bat-файлах.
В Launcher удобно создавать новый проект: при этом создаётся папка с каркасом для приложения — заботливо заполненным конфигурационным файлом app.yaml и демо-приложением «Hello world» в файле main.py. Идём в меню File -> Create New Application, вводим имя для нашего проекта, указываем путь к папке, в которой он будет находиться, и порт для запуска локального dev-сервера. Готово! Запускаем приложение кнопкой Run, ждём, пока рядом с именем проекта нарисуется зелёная иконка «Play», и вот по адресу http://localhost:номер_порта_dev-сервера
мы видим приветствие. Если что-то пошло не так, вместо иконки «Play» — восклицательный знак и dev-сервер не запустился, по нажатию на кнопку Logs доступен лог приложения с информацией для отладки.
app.yaml
Все настройки приложения хранятся в файле app.yaml:
application: имя_приложения
— это идентификатор приложения, который мы указали при его создании. В процессе разработки на локальном компьютере он может быть любым, но к тому моменту, когда вы решите загрузить приложение с локальной машины на сервера Google (кнопка Deploy в App Engine Launcher), у вас должен быть зарегистрирован аккаунт App Engine, а в нём приложение с таким же именем, как и этот идентификатор. Учитывая, что имя приложения при регистрации в аккаунте App Engine должно быть уникально, не исключено, что то, которое вы указали при его создании на локальном компьютере уже занято, и его придется сменить.version: 1
— указывает версию приложения. App Engine сохраняет копию приложения для каждой используемой версии. После обновления существующего проекта, в административной консоли можно указать, что основным всё ещё является предыдущий релиз, и при этом тестировать новый выпуск. Так же, в случае необходимости, всегда можно откатиться к любой из сохранённых версий проекта.runtime: python27
— среда исполнения приложенияapi_version: 1
— версия API среды исполнения. На данный момент — это единственная версия для Python; другие могут быть добавлены Google позже, при этом приложение продолжит использовать ту, для которой оно было написано.threadsafe: yes
— указывает, что один экземпляр приложения поддерживает обработку нескольких одновременных запросов.- Раздел
handlers
содержит список шаблонов URL, для каждого из которых указывается способ обработки запросов. Способов два: App Engine может выполнить код скрипта, чтобы определить ответ для данного URL, либо вернуть статический файл (например: *.jpg, *.css, *.js), загруженный во время развёртывания приложения. - В разделе
libraries
указываются пакеты расширения Python из состава App Engine (папка lib в каталоге с установленным SDK), которые должны быть доступны приложению.
Про синтаксис YAML можно узнать здесь. А тут лежит полное описание возможных параметров конфигурации приложения.
web.py
Вообще-то, вместе с App Engine поставляется web-фреймворк webapp2, и, уверен, он прекрасно подошёл бы для написания блога, но когда я начал выбирать компоненты, которые буду использовать, то почему-то решил, что webapp2 заточен специально под App Engine и больше нигде работать не будет. Теперь мне известно, что это не так, но на тот момент было решено искать альтернативу. В итоге был выбран web.py, как универсальный, легковесный фреймворк, совместимый с App Engine. Он даже похож на webapp2, или, скорее, webapp2 похож на него. Утверждается, что web.py вдохновил создателей фреймворка webapp, который в дальнейшем эволюционировал в webapp2.
Качаем дистрибутив с GitHub, берём из него папку web и кладём её в каталог с нашим приложением. Файл app.yaml сразу после создания приложения из App Engine Launcher выглядит следующим образом:
application: engineapp
version: 1
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: /favicon.ico
static_files: favicon.ico
upload: favicon.ico
- url: .*
script: main.app
libraries:
- name: webapp2
version: "2.5.1"
Меняем в нём:
threadsafe: yes
на
threadsafe: false
и
script: main.app
на
script: main.py
Правки, которые мы внесли, вызваны тем, что экземпляр приложения web.py запускается методом, отличным от метода запуска webapp2, но суть не меняется: все запросы, за исключением обращений к файлу favicon.ico, будут по прежнему передаваться на обработку скрипту main.py.
Очищаем файл main.py. Импортируем модуль web.py:
import web
Создаём экземпляр приложения:
app = web.application(urls, globals())
Указываем метод, для его запуска:
if __name__ == "__main__":
app.cgirun()
Приложение app
запускается методом cgirun()
, и это ключевой момент при работе web.py на App Engine. Если вы посмотрите документацию на сайте фреймворка, в ней для запуска приложения используется метод run()
. На App Engine он работать не будет.
Как вы можете заметить, при создании приложения используется переменная urls
, — это кортеж, описывающий структуру URL-адресов сайта.
Добавим для блога главную страницу:
urls = (
'/', 'mainPage'
)
Сначала идёт регулярное выражение, соответствующее URL-адресу, затем — имя класса, которому будет передана обработка запроса.
Создадим класс mainPage
:
class mainPage:
def GET(self):
return 'Hello world!'
В итоге, файл main.py должен выглядеть следующим образом:
import web
urls = (
'/', 'mainPage'
)
class mainPage:
def GET(self):
return 'Hello world!'
app = web.application(urls, globals())
if __name__ == "__main__":
app.cgirun()
Теперь при открытии главной страницы блога, HTTP GET-запрос передается классу mainPage
, а он в ответ возвращает строку Hello world!
Чудесно! Но вместо простого текста нам нужен HTML, а отдавать его таким же способом, смешивая представление с программным кодом, — не самая хорошая идея. Пришло время подключить шаблонизатор.
Продолжение следует...
P.S. Изначально я предполагал, что всего будет 2 части, но, должен признать, я недооценил количество тем, которые потребуется затронуть для создания целостной картины. Мне бы не хотелось опускаться до copy-paste кода с краткими комментариями, поэтому обещанные Datastore и Memcache будут чуть позже, сразу после Jinja2.
Автор: wombatonfire