Евгений Загородний
Pylons: python-фреймворк
Эта статья посвящена знакомству с веб-фреймворком Pylons, написанном на языке python.Поскольку функциональность подавляющего большинства веб-приложений сводится к обработке форм и взаимодействию с базой данных, будет рассмотрено создание простейшего приложения, которое... обрабатывает формы и взаимодействует с базой данных ;)
Материал, изложенный здесь, следует воспринимать как отправную точку для дальнейшего знакомства с возможностями фреймворка.
Предполагается, что читатель знаком с концепциями архитектуры MVC.
Установка
Установка Pylons довольно проста, и при отсутствии непредвиденных обстоятельств производится «в одну команду».Один из способов установки — с помощью утилиты easy_install, которая входит в коллекцию setuptools.
Другой способ, не требующий установленных setuptools — с помощью одного скрипта ez_setup.py.
Кроме того, в коллекции портов FreeBSD имеется порт www/py-pylons, которым я и воспользовался. Неожиданностей при установке не возникло.
Подробное описание установки и последующих настроек можно найти в разделе Installing Pylons официальной документации.
Создание проекта
Сразу отмечу одну из характерных особенностей Pylons — он интенсивно использует сторонние компоненты. Сам фреймворк преимущественно играет роль связующего звена между ними. Требовательные к гибкости разработчики оценят возможность замены используемых компонентов на другие, аналогичные по функциональности, но более привычные / подходящие для определенного круга задач. Имеем такой вот «конструктор» :)Для создания «скелета» проекта используется скрипт Paste:
> paster create -t pylons basic
Это команда создаст в текущей директории проект basic. Описание структуры проекта можно найти в разделе Getting Started официальной документации.
Все, что касается конкретного проекта находится в basic/basic (аналог app в CakePHP или apps в Symfony).
Собственно, это было необходимым минимумом для того, чтобы можно было запустить сервер, что мы и сделаем (из директории basic):
> paster serve --reload development.ini
Это запустит веб-сервер, по умолчанию — сервер из модуля Pylons, который будет обслуживать localhost (то есть только ту машину, на которой был запущен). Это в большинстве случаев удобно для разработки и отладки. На production-сервере можно либо сконфигурировать Pylons для работы с имеющимся веб-сервером, например, Apache с mod_python, либо настроить имеющийся веб-сервер для проксирования запросов на веб-сервер Pylons.
Опция --reload нужна для того, чтобы сервер отслеживал изменения файлов, и при необходимости автоматически перезагружался. Это избавит разработчика от необходимости делать это вручную.
Если все прошло успешно, то на http://localhost:5000/ мы увидим «умолчальную» страничку.
Добавляем контроллер
Начнем с добавления в наш проект контроллера welcome. Для этого, опять же, воспользуемся Paste:> paster controller welcome
После этого появится файл basic/controllers/welcome.py со следующим содержимым:
from basic.lib.base import * class WelcomeController(BaseController): def index(self): # Return a rendered template # return render_response('/some/template.html') # or, Return a response object return Response('Hello World')
Как видим, вновь созданный конроллер имеет единственное действие (action) index. Его результат можно увидеть на http://localhost:5000/welcome — простая страничка с текстом Hello World, результатом return Response('Hello World').
Что возвращает контроллер?
Есть два способа для того, чтобы вернуть значение из контроллера.Первый — вернуть объект Response. Конечным результатом будет страница, содержащая строку, которой инициализировался объект Response (как в предыдущем примере с Hello World).
Второй — воспользоваться методом render_response, который принимает в качестве аргумента название шаблона (template). Шаблоны находятся в директории templates.
Честно говоря, трудно представить, в каких случаях в реальных приложениях будет целесообразно использование первого способа. Поэтому в дальнейшем будет использоватся только второй способ. Для этого понадобится создать шаблон, чем мы сейчас и займемся.
Добавление шаблона
Как уже было замечено, шаблоны нашего проекта хранятся в директории basic/templates. Создадим новый шаблон basic/templates/intro.html:Hello.<br /> You can <a href="/welcome/add">add a new record</a> or <a href="/welcome/list">list existent records</a>.<br /> Good luck!
Как можно заметить, в шаблон не были добавлены некоторые необходимые теги, например <html>. Это было сделано намеренно — «обертка» будет общей для всех страниц проекта. Она определяется в basic/templates/autohandler. Добавим для наших страничек простое оформление из header-а footer-а:
<html> <head><title>Basic web application</title></head> <body> <div class="header"><h1>Welcome to Pylons framework!<h1><hr /></div> <div class="content"> % m.call_next() </div> <div class="footer"><hr />powered by <a href="http://pylonshq.com/">Pylons</a></div> </body> </html>
Обратите внимание на строчку % m.call_next() — она предназначена для шаблонного движка Myghty, используемого в Pylons (как уже упоминалось, Pylons напоминает своеобразный «конструктор», и вместо Myghty можно использовать другой движок, удобный Вам).
То, что в Pylons называется template — в CakePHP называется view.
То, что я назвал «оберткой» — в CakePHP называется layout.
Использование шаблона в контроллере
Теперь изменим действие index контроллера welcome (basic/controllers/welcome.py), чтобы оно использовало шаблон intro:def index(self): return render_response('intro.html')
После этого на http://localhost:5000/welcome будет находится наш шаблон, оформленный в соответствии с «оберткой».
Ссылки на этой страничке пока что не работают, но нажав на них можно ознакомиться с debuger-ом фреймворка.
Helpers
Ни один уважающий себя фреймворк не обходится без так называемых helper-ов — функций, облегчающих генерирование html-кода и делающих шаблоны более читабельными. Pylons — не исключение, и сейчас мы воспользуемся helper-ами для создания формы.Создадим шаблон basic/templates/add-record.html:
<% h.form(h.url(action='save'), method='post') %> Record title: <% h.text_field('title') %> <br /> Record description: <% h.text_field('description') %> <br /> <% h.submit('Add record') %> <% h.end_form %>
Как видно, содержимое шаблона говорит само за себя. Комментария заслуживает только префикс h перед вызовами методов. h — это одна из глобальных переменных, предоставляемых Pylons. Она используется для обращения к helper-ам.
Снова добавим в контроллер welcome новое действие add, использующее этот шаблон:
def add(self): return render_response('add-record.html')
Теперь одна из ссылок на странице http://localhost:5000/welcome стала рабочей.
Обработка формы
После заполнения и отправки формы на http://localhost:5000/welcome/add управление перейдет к действию save (см. action='save'). Наша задача — принять данные из формы и обработать их.Данные, переданные через GET или POST запросы, доступны в контроллере как request.params['имя_поля']. Продемонстрируем это, заодно рассмотрев передачу данных из контроллера в шаблон. Добавим в контроллер welcome действие save:
def save(self): c.title = request.params['title'] c.description = request.params['description'] return render_response('save-record.html')
c — это еще одна глобальная переменная Pylons, предназначенная для передачи значений в шаблон.
Добавим шаблон basic/templates/save-record.html:
Record posted<br /> Title: <% c.title %><br /> Description: <% c.description %><br />
Заполнив форму на http://localhost:5000/welcome/add и отправив ее, мы перейдем к действию save, которое пока что только выводит переданные значения на страницу.
Теперь самое время заняться настройкой связи с базой данных.
Настройка связи с базой данных
И снова дает знать о себе «конструктороподобность» Pylons: выбор движка для взаимодействия с базой данных, такого как SQLAlchemy или SQLObject, остается за нами. Вплоть до того, что можно вообще отказаться от его использования в пользу стандартного API.Воспользуемся набирающим популярность SQLAlchemy. Прежде всего его необходимо установить, включив поддержку используемого сервера базы данных (в моем случае — MySQL). Инструкции по установке есть в официальной документации. Кроме того, порт databases/py-sqlalchemy опять-таки присутствует в коллекции портов FreeBSD.
Приступим к связванию нашего проекта с базой данных. Прежде всего, добавим в секцию [app:main] файла development.ini (предназначенного для Paste) строку, указывающую, как соединиться с базой данных, например
sqlalchemy.dburi = mysql://root@localhost/basic
Эта строка будет использована в качестве аргумента для create_engine; ее формат описан в разделе Database Engines документации по SQLAlchemy.
Далее, в файле basic/models/__init__.py инициализируем метаданные для связи с базой данных и проассоциируем их с объектом, в виде которого данные из таблицы будут представлены в нашем приложении:
from sqlalchemy import * from sqlalchemy.ext.assignmapper import assign_mapper from pylons.database import session_context as ctx meta = MetaData() records_table = Table('records', meta, Column('id', Integer, primary_key=True), Column('title', String(40)), Column('description', String(40)), ) class Record(object): def __str__(self): return self.title record_mapper = assign_mapper(ctx, Record, records_table)
В реальных приложениях со сложными моделями класс Record будет дополнен вспомоготельными методами.
И, наконец, дополним basic/websetup.py действиями, необходимыми для инициализации базы данных. В его начале импортируем модели проекта:
А в методе setup_config добавим следующее:
from pylons.database import create_engine engine = create_engine(conf['sqlalchemy.dburi']) model.meta.connect(engine) model.meta.create_all()
Убедившись, что сервер баз данных запущен и создав пустую базу данных с названием, указанным в sqlalchemy.dburi, можно приступить к инициализаци базы данных. Эта процедура выглядит одинаково как во время разработки, так и при установке завершенного приложения на сервер:
> paster setup-app development.ini
После этого база данных будет содержать необходимые таблицы.
Обращение к модели
Итак, в наших руках теперь вся мощь SQLAlchemy. Переделаем действие save так, чтобы оно действительно сохраняло запись в базу данных:def save(self): record = model.Record(); record.title = request.params['title'] record.description = request.params['description'] record.flush() h.redirect_to(action='saved')
Код в комментариях не нуждается — создается новый объект «запись», заполняется данными из формы, и, наконец, сохраняется в базе данных (record.flush()).
Однако, обратите внимание на последнюю строчку — вместо привычного return_response указывается перенаправление на другое действие, saved. Это сделано для того, чтобы в том случае, если после успешного сохранения пользователь обновит в броузере содержимое страницы, информация в POST-запросе не посылалась повторно.
Разумеется, действие saved необходимо определить:
def saved(self): return render_response('save-record.html')
Шаблон save-record.html, которым мы воспользовались, также нуждается в правке, чтобы соответствовать своему новому предназначению:
Record saved.<br /> <a href="/welcome/add">Add another record</a><br /> <a href="/welcome/">Return</a><br />
И наконец...
Что ж, осталось, используя уже знакомые средства, «оживить» вторую ссылку на http://localhost:5000/welcome. Для этого нужно определить действие listdef list(self): c.records = model.Record.select() return render_response('list-records.html');
и создать для него шаблон list-records.html
List of records: <table> <tr><th>title</th><th>description</th></tr> % for record in c.records: <tr><td><% record.title %></td><td><% record.description %></td></tr> % </table> <a href="/welcome">Return</a>
Заключение
Итак, было рассмотрено создание приложения, использующего базовые возможности фреймворка Pylons — создание контроллеров, шаблонов, моделей; обработка форм, взаимодействие с базой данных; использование шаблонного движка и helper-ов.Изложенный материал может помочь в дальнейшем освоении возможностей Pylons, которые здесь остались без внимания — URL routing, валидация форм, автоматизация установки готового приложения на сервер, интеграция с библиотеками prototype и script.aculo.us для создания AJAX-приложений и др.
Ссылки
Pylons — python фреймворкMyghty — шаблонный движок
SQLAlchemy — движок для связи в базой данных
Обзор Pylons
Пробуем Pylons, часть 1: install, db setup
Пробуем Pylons, часть 2: views
Стандарт WSGI
Production deployment using supervisor Apache as a reverse proxy
Последние комментарии:
исправления | Автор |
---|---|
2Ard Спасибо за замечания, внес в статью исправления. |
|
dymko | |
Спасибо, одна из очень немногих статей на русском языке. И полезная, к тому же. Было бы продолжение – было бы замечательно. Т.к. по пилонам практически ничего нет, днём с огнём не сыщешь. |
|
Ard | |
«Далее, в файле инициализируем метаданные для связи с базой данных и проассоциируем их с объектом, в виде которого данные из таблицы будут представлены в нашем приложении:» не понятно о каком файле идет речь в разделе |
|
Ard | |
Спасибо за туториал! Дело в освоении питона для веба движется :) там у Вас ошибочка... Снова добавим в контроллер “welcome” новое действие “add”, использующее этот шаблон: def index(self): return render_response('add-record.html') Надо: def add(self): |
|
Обсудить (комментариев: 4)