Python: Веб-разработка без фреймворков (часть 1)
Щетинин СергейОпубликовано 8.04.2008 в Python, Разработка, Статьи
Каждый разработчик тщательно выбирает свой инструментарий и чем лучше он им владеет, тем эффективнее его работа и тем более востребованы его услуги. В то же время многие программисты гордятся своей ленью и ищут такие инструменты, которые делали бы за них как можно больше работы. При этом, на мой взгляд, забывают, что бесплатный сыр только в мышеловке и гоняются за иллюзорным «лучшим» фреймворком тщательно сверяя какой из них делает больше работы: Zope, ROR или Django? Мой опыт говорит о том, что время на изучение фреймворков и подстройка под их ограничения почти никогда не окупается, а пользуясь минимальным инструментарием, с которым я хочу вас ознакомить, можно добиться гораздо лучших результатов.
WSGI
Не так давно библиотек и фреймворков для веб-разработки на Python было очень много, и взаимодействовали они между собой не наилучшим образом. Выбрав для разработки одно решение приходилось придерживаться его и в дальнейшем. Разрешением этой проблемы многие считали выбрать один-два главных фреймворка и сконцентрироваться на их разработке, таким образом сделав остальные ненужными. Такая консолидация решила бы проблемы с взаимодействием разных частей, но и минусов у неё порядочно. Ведь так много библиотек возникло не зря, и причина этого именно в том что нет очевидно предпочтительного подхода к веб-разработке.
Решение подоспело в виде стандарта WSGI (PEP-333). Это сверх-компактная спецификация, которая решает как вопросы взаимодействия разных компонент веб-приложений, так и связки между этими приложениями и HTTP-сервером.
Вкратце, WSGI (Web Server Gateway Interface) требует от приложения предоставлять следующий интерфейс:
def app(environ, start_response):
"""
(dict, callable( status: str,
headers: list[(header_name: str, header_value: str)]))
-> body: str or iterable of strings
“”"
Т.е. приложение будет вызвано с двумя аргументами. Первый – словарь environ, содержащий различные данные о запросе, второй – функция запускающая процесс ответа на запрос. В основном содержимое environ совпадает с содержимым переменных окружения CGI скрипта при аналогичном запросе, откуда и происходит имя этого аргументa, это же позволяет использовать уже имеющиеся средства для разбора строки запроса итп. Назначение start_response проще показать на примере, а возвращать WSGI приложение должно либо строку, либо итератор по строкам, т.е. функция может быть генератором и «скармливать» веб-серверу ответ по частям. Например:
import cgi
def hello_app(environ, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
yield “Hello, ”
form = cgi.FieldStorage(environ=environ)
name = form.getfirst(’name’, ’stranger’)
yield name
Удобство использования WSGI заключается, конечно, не в том, что мы можем писать такой код, а в том, что предоставив такой интерфейс, мы получаем доступ к множеству совместимых библиотек. Например, мы элементарно можем запустить сервер с вышеуказанным приложением:
from paste.httpserver import serve
serve(hello_app)
Мы можем также предоставить его через FastCGI, SCGI или еще какой-нибудь диковинный протокол общения между HTTP-сервером и сервером приложений. Существует также mod_wsgi, модуль Apache, позволяющий в считанные минуты запустить ваше приложение через этот сервер, причем с отличной интеграцией с его инфраструктурой.
Ну и, конечно же, мы можем вызывать другие WSGI приложения и обрабатывать их результаты (о чем будет сказано в разговоре о middleware). Этот стандарт к тому же делает возможным библиотеки тестирования веб-приложений, не привязанные ни к каким фреймворкам. В результате библиотек для веб-разработки врядли стало меньше, ведь создавать новые теперь куда проще, но проблема совместимости была решена. Теперь любой фреймворк, вне зависимости от того каким образом он сообщается с вашим кодом, предоставляет WSGI. Различные приложения, не использующие сторонних фреймворков, также доступны через WSGI (например Trac).
PythonPaste
PythonPaste (paste – тесто) это замечательное собрание различной функциональности реализованной для WSGI и общей для разных фреймворков. Если вы заглянете своей любимой библиотеке под капот и не найдете там Paste, то выбор ваш возможно не так уж хорош. Впрочем, сам Paste настолько удобен, что ознакомившись с его возможностями, не должно возникнуть желания использовать какой-либо фреймворк вообще.
Например, в нем есть готовая поддержка самых разных способов аутентификации (Basic, Digest, form, signed cookie, auth_tkt), поддержка корректной и удобной генерации ответов и заголовков (к примеру редиректы, Cache-control, Expires, gzipper и прочие). Различные базовые средства комбинации приложений (URLMap, Cascade, Recursive), статических данных (с учетом Etag, If-Modified итп). Скажем так:
from paste.urlmap import URLMap
from paste.fileapp import FileApp
root_app = URLMap()
root_app['/static'] = FileApp(’/var/www/static/’)
from paste.auth.digest import digest_password, AuthDigestHandler
def private_app(environ, start_response):
remote_user = environ['REMOTE_USER']
app = FileApp(’/home/%s/htdocs/’ % remote_user)
return app(environ, start_response)
def authfunc(environ, realm, username):
return digest_password(realm, username, username) # password == username
private_wrapped = AuthDigestHandler(private_app, “Private area”, authfunc)
root_app['/private'] = private_wrapped
Как видите, кода написано минимум, а часть сайта уже защищена паролем и соответствует разным папкам на диске в зависимости от имени пользователя. Представить себе, что нечто подобное можно записать короче и понятней, трудно.
Можно также предоставлять статические файлы прямо из архива (ArchiveStore), есть поддержка сессий, возможность отслеживать прогресс загрузки на сервер больших форм, и прочее и прочее.
PythonPaste для отладки
Особо радуют средства для отладки приложений. Тут и возможность приложения автоматически перезапускаться при изменении части исходных кодов, и профайлер для каждого запроса, и возможность слать отчеты об ошибках на почту (или сохранять их локально). Можно валидировать все [X]HTML ответы сервера, есть те самые средства тестирования WSGI приложений итд итп. Есть даже возможность интерактивной отладки прямо в браузере. На этом стоило бы остановиться особо, но это лучше один раз увидеть, чем сто раз прочитать, просто запустите этот код и откройте в браузере http://localhost:8080/. (Также можно посмотреть скринкаст).
from paste.evalexception.middleware import EvalException
def error_app(environ, start_response):
raise ValueError
from paste.httpserver import serve
serve(EvalException(error_app))
Далее
В следующих частях я собираюсь рассказать про использование WebOb, написание middleware, возможности mod_wsgi и вопросы конфигурации WSGI приложений.
Понравилась статья? Подпишись на обновления по RSS/E-mail




(16 голосов, средний: 4.44 из 5)
Сергей спасибо за интересную статью.
Согласен отчасти по поводу окупаемости, но мне кажется что Pylons здесь исключение, так как он не навязывает а рекомендует. RoR тоже неплох, а вот Django слишком ограничивает творчество, что не свойственно для Python фреймворков.
Может для зубров которые “на ты” с WSGI Pylons и не нужен, но мы с нуля сколотили на нем свой собственный мини-фреймворк и очень довольны. И результатом и скоростью разработки.
Хотя конечно многие вещи мы выкинули или переточили, но начинать совсем с WSGI было бы сложнее и наверное мы бы не писали на Python совсем
Совсем чистый WSGI и вправду не всегда самый удобный вариант, но вот в следующей статье я расскажу про WebOb, а по сравнению с ним у фреймворков уже очень мало преимуществ. Я как раз за такой подход как у вас — составлять свой мини-фреймворк, или скорей все таки, библиотеку для веб-разработки. Pylons собираюсь тоже чуток поругать.
ИМХО у каждой задачи свое решение, где-то подойдет фреймворк(опять таки выбор зависит от задачи), где то чистый питон.
вообще если подумать и отбросить проф. амбиции то разработчику должно быть глубоко пофигу на чем писать и как писать, главное чтобы заказчик был доволен.
Я думаю что популярность фреймворков связана с тем, что неопытный программист сначала ищет чего бы почитать на тему веб-разработки (и это правильно), а статьи и книги в основном о том, как писать при помощью разных навороченных фреймворков. Несколько упрощая ситуацию можно сказать что по Zope можно написать сотню книг, а по Paste едва ли одну. Zope едва ли в 100 раз полезней. То же касается Java vs. Python, REST vs. SOAP / WS-* итд.
Спасибо, обязательно почитаю. Сам пока не добрался
Очень интересно, так как Пилоны, начиная с 0.9.7, используют request/response objects from WebOb.
Не знал что уже используют. =) Молодцы значит.
Пошел читать про изменения в Пилонах и попалась статья про SQLAlchemy / Elixir и про то что по большому счету последний — зло. Я об этом тоже собираюсь кое-что написать, и даже пожалуй радикальнее, но пока что рекомендую ознакомиться с тем что есть.
Спасибо, познавательно. Даже для такого полного
чурбаначайника в веб-разработке как я.ЗЫ: Сергей, у тебя сайт лежит.
bialix, спасибо, про сайт знаю — хадвер подвел.
Сергей, в SQL Alchemy помимо Elixir есть еще плагин Declarative (http://www.sqlalchemy.org/docs/04/sqlalchemy_ext_declarative.html). С ним работа, конечно, не настолько простая и гибкая как с Elixir, зато вся гибкость SQL Alchemy остается.
Александр, спасибо, гляну подробней. Хотя, страшно сказать, но я на данный момент от ORM отказался совсем. Для веб-приложений с какого-то момента так вообще декларации для таблиц не пишу — сразу в базе их создаю а в питоне
Table("...", dbmeta, autoload=True). Работает всё, надо сказать, ну ничуть не хуже.Спасибо, статья добавила оптимизма. Который день бъюсь над Hellow world в Django и ничего не получается. Т.е. не могу настроить всю связку. Мне проще с нуля разрабатывать, чем настраивать интеграцию всего этого кампота c фрейворками. Пожалуйста приведите пример или подскажите где почитать пошаговую, понятную для чайников инструкцию, настройки Apache+WSGI+Python+IDE(например Eclipse/PyDev) для разработки чисто под WSGI.
Как выполнить код приведенный в статье? Ибо “просто запустить” код я не могу.
На всякий случай повторю, что не знаю насколько хорошо сработает такой подход для новичков / чайников и поэтому стараюсь давать материал таким образом чтобы нужно было часть шагов выполнять самому, если с ними возникают проблемы, то возможно не стоит слепо копировать всё остальное. Вообще для новичков я пожалуй порекомендовал бы CherryPy, там достаточно быстро можно приступить к работе.
Приведенный тут код как раз можно просто запускать (см. упомянутый paste.httpserver). Ну и прочитайте остальные статьи в серии, в частности http://www.developers.org.ua/archives/mlk/2008/05/20/python-webdev-no-frameworks-p4/