Python и App Engine для web-разработки. Пишем лёгкий и быстрый блог. Часть 2

в 20:05, , рубрики: google app engine, python, web-разработка, Веб-разработка, метки: , ,

Часть 1

Чтобы начать использовать 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

* - обязательные к заполнению поля