Пробуем Pylons, часть 1: install, db setup
clegОпубликовано 27.04.2007 в Статьи
Всякий человек естественно пытается облегчить себе жизнь. Программисты – ярко выраженное доказательство этого принципа. Так уж сложилось, что по ходу работы мне необходимо создавать множество мелких Web-приложений, для решения небольших текущих задач. Ну а поскольку использование PHP мне не доставляет удовольствия чисто эмоционально, я решил попробовать для этих целей Python.
Для начала был опробован очень неплохой пакет httpy, но его функциональность в области “усиленного облегчения жизни” явно очень аскетична. Услышав краем уха волшебное слово фреймворк (как это лучше всего перевести на русский?) я ринулся на «раскопки» этой информации.
В ходе опробования самых распространенных Python фреймворков я для себя остановился на Pylons.
Хочу сразу пояснить, что TurboGears я пока не рассматривал подробно, так как у них до сих пор нет версии для Python 2.5, а в Django до сих пор по моему дилетантскому мнению обладает слишком большим количеством «магии».
К плюсам Pylons можно отнести во-первых заимствование лучший идей мегамодного Rails, во-вторых очень высокая гибкость, выражающаяся в поддержке множества шаблонных движков, ORM и т.д. я надеюсь что в ходе изучения смогу попробовать многие их них изучив массу полезных инструментов.
Для начала, рассмотрим установку данного фреймворка. Проще всего это сделать используя скрипт easy_install (если он уже установлен в системе).
<pre>$easy_install Pylons</pre>
Для тех, чей доступ в интернет перекрыт злобными прокси-серверами, я бы порекомендовал установить переменную окружения HTTP_PROXY, равную URL прокси-сервера. По крайней мере, именно это решение позволило мне насладиться автоматической установкой Pylons.
Если скрипта easy_install у вас нет, то вам необохдимо скачать http://peak.telecommunity.com/dist/ez_setup.py и выполнить его следующим образом.
<pre>$ python ez_setup.py Pylons</pre>
Кроме установки базовых компонент Pylons, можно инсталлировать еще ряд дополнительных. Делается это командой:
<pre>$easy_install Pylons[компонент]</pre>
Где компонент может быть одним из следующих.
- pudge – поддержка сборки документации (подробности тут). Разработчики отмечают что часть инструментов данного проекта все еще находится в разработке и нестабильна.
- genshi, cheetah, kid – поддержка соответсвующих шаблонных движков (подробности тут)
- full – все вышеперечисленное
Обновить Pylons так же очень просто. Независимо от варианта установки, обновление делается одной командой:
<pre>$ easy_install -U Pylons</pre>
Хотя следует отметить, что у меня после обновления таким образом до 0.9.5 Pylons оказался поломан, но разбираться в чем была причина – честно говоря было лень, и переустановка решила все проблемы.
Кстати, для пользователей ОС для домохозяек рекомендуется включить в PATH каталог Scripts, расположенный в каталоге python. Это поможет проще использовать утилиту paster.
Теперь давайте опробуем работу свежеустановленного ферймворка на каком-нибудь конкретном примере.
В роли примера, пожалуй, выступит онлайновый телефонный справочник.
Для начала создадим пустой проект. Для этого необходимо перейти в каталог проектов и там выполнить команду:
<pre>$ paster create --template=pylons phones</pre>
После этого будет создана структура каталогов будущего проекта. Описывать ее подробно я не буду, так как это неплохо сделано в руководстве.
Для теста я использую обычно базу SQLite (хозяевам Python 2.5 уже повезло иметь ее в дистрибутиве, остальным придется доставить соответствующий пакет).
Настроим базу данных используемую нашим приложением. Для этого необходимо отредактировать файл development.ini в корне проекта, поменяв там значение параметра:
<pre>sqlalchemy.dburi = sqlite:///%(here)s/phones.db</pre>
Теперь приступим к созданию моделей. Модели можно редактировать прямо в файле __init__.py в каталоге phones/models
Предварительная версия модели выглядит так:
<pre>from sqlalchemy import *
from sqlalchemy.ext.assignmapper import assign_mapper
from pylons.database import create_engine
from pylons.database import session_context as ctx
meta = MetaData()
persons_table = Table('persons', meta,
Column('id', Integer, primary_key=True),
Column('name', String(40)),
Column('department', Integer, ForeignKey('departments.id')),
Column('email', String(40)),
Column('phone', String(16)),
Column('phone_int', String(6))
)
contacts_table = Table('contacts', meta,
Column('id', Integer, primary_key=True),
Column('type', Integer),
Column('contact', String(40)),
Column('person_id', Integer, ForeignKey('persons.id'))
)
departments_table = Table('departments', meta,
Column('id', Integer, primary_key=True),
Column('name', String(40))
)
class Person(object):
def __str__(self):
return "%s [%s]" % (self.name, self.department)
class Contact(object):
def __str__(self):
return self.contact
contact_mapper = assign_mapper(ctx, Contact, contacts_table)
person_mapper = assign_mapper(ctx, Person, persons_table, properties={'contacts':relation(Contact)})</pre>
Мы создаем три таблицы:
- persons – основная таблица с контактной информацией
- contacts – дополнительные контактные данные (если понадобится что-то нестандартное)
- departmens – таблица подразделений
Кроме того, создаем обеъкты для ORM, которые связываем с соответствующими таблицами функцией assign_mapper.
Теперь нам необходимо обеспечить развертывание данной базы при инсталляции приложения. Для этого в файл websetyp.py, находящийся в корне проекта необходимо добавить следующие строки:
<pre>import paste.deploy
from pylons.database import create_engine
import phones.models as model
def setup_config(command, filename, section, vars):
conf = paste.deploy.appconfig('config:' + filename)
conf.update(dict(app_conf=conf.local_conf, global_conf=conf.global_conf))
paste.deploy.CONFIG.push_process_config(conf)
uri = conf['sqlalchemy.dburi']
engine = create_engine(uri)
print "Connecting to database %s" % uri
model.meta.connect(engine)
print "Creating tables"
model.meta.create_all()</pre>
Теперь, если все сделано правильно, команда
<pre>$ paster setup-app development.ini</pre>
приведет к созданию нашей базы.
Понравилась статья? Подпишись на обновления по RSS/E-mail

(3 голосов, средний: 4 из 5)
Исходник поправь, код съехал.
Статья понравилась. Жде продолжения.
Використовуйте тег <pre> для блоків коду
спасибо
я использовал тег
но как его недостаточно. сейчас исправлю.молодец
Отличная работа!
Про “чёрную магию” Django — ничего подобного. Не будем плодить мифы?
я не говорю про черную… просто в джанго многие вещи спрятаны больше “вглубь”, по сравнению с другими фреймворками. это для новичка типа меня и кажется более “магическим”
я всего лишь высказываю свое мнение.
Откуда у Contact возьмется атрибут phone? В схеме phone принадлежит Person.
мдя. это пролезло из старой версии.
исправил.
Что-то сначала easy_install поругался:
error: Could not find suitable distribution for Requirement.parse(’nose>=0.9.2,
Пилоны при инсталляции не смогли поставить Nose нужной версии. Видать что-то натуплено с описанием зависимости
Но без nose ЕМНИП все должно фпалне работать.
Вроди все по примеру сделал, но при “paster setup-app” вылазит:
“import phones.models as model
ImportError: No module named models”
В каком “py” они должны лежать, я так понимаю что этот модуль автоматом созадется paster-ом?
Можно полный трейс?
создаем проект
c:\web\Python25>paster create –template=pylons phones
Selected and implied templates:
pylons#pylons Pylons application template
Variables:
egg: phones
package: phones
project: phones
Creating template pylons
Creating directory .\phones
Recursing into +egg+.egg-info
Creating .\phones\phones.egg-info/
Copying paste_deploy_config.ini_tmpl_tmpl to .\phones\phones.egg-info\paste_
deploy_config.ini_tmpl
Recursing into +package+
Creating .\phones\phones/
Copying __init__.py_tmpl to .\phones\phones\__init__.py
Recursing into config
Creating .\phones\phones\config/
Copying __init__.py_tmpl to .\phones\phones\config\__init__.py
Copying environment.py_tmpl to .\phones\phones\config\environment.py
Copying middleware.py_tmpl to .\phones\phones\config\middleware.py
Copying routing.py_tmpl to .\phones\phones\config\routing.py
Recursing into controllers
Creating .\phones\phones\controllers/
Copying __init__.py_tmpl to .\phones\phones\controllers\__init__.py
Copying error.py_tmpl to .\phones\phones\controllers\error.py
Copying template.py_tmpl to .\phones\phones\controllers\template.py
Recursing into lib
Creating .\phones\phones\lib/
Copying __init__.py_tmpl to .\phones\phones\lib\__init__.py
Copying app_globals.py_tmpl to .\phones\phones\lib\app_globals.py
Copying base.py_tmpl to .\phones\phones\lib\base.py
Copying helpers.py_tmpl to .\phones\phones\lib\helpers.py
Recursing into model
Creating .\phones\phones\model/
Copying __init__.py_tmpl to .\phones\phones\model\__init__.py
Recursing into public
Creating .\phones\phones\public/
Copying index.html_tmpl to .\phones\phones\public\index.html
Recursing into templates
Creating .\phones\phones\templates/
Recursing into tests
Creating .\phones\phones\tests/
Copying __init__.py_tmpl to .\phones\phones\tests\__init__.py
Recursing into functional
Creating .\phones\phones\tests\functional/
Copying __init__.py_tmpl to .\phones\phones\tests\functional\__init__.py
Copying test_models.py_tmpl to .\phones\phones\tests\test_models.py
Copying websetup.py_tmpl to .\phones\phones\websetup.py
Copying MANIFEST.in_tmpl to .\phones\MANIFEST.in
Copying README.txt_tmpl to .\phones\README.txt
Copying development.ini_tmpl to .\phones\development.ini
Recursing into docs
Creating .\phones\docs/
Copying index.txt_tmpl to .\phones\docs\index.txt
Recursing into ez_setup
Creating .\phones\ez_setup/
Copying README.txt to .\phones\ez_setup\README.txt
Copying __init__.py to .\phones\ez_setup\__init__.py
Copying setup.cfg_tmpl to .\phones\setup.cfg
Copying setup.py_tmpl to .\phones\setup.py
Copying test.ini_tmpl to .\phones\test.ini
Running c:\web\Python25\python.exe setup.py egg_info
Adding Pylons to paster_plugins.txt
Adding WebHelpers to paster_plugins.txt
устанавливаем:
Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.
c:\web\Python25\phones>paster setup-app development.ini
c:\web\Python25\phones\phones\websetup.py:7: DeprecationWarning: pylons.database
is deprecated, and will be removed from a future version of Pylons. SQLAlchemy
users are recommended to migrate to SAContext (http://cheeseshop.python.org/pypi
/SAContext) for similar functionality
from pylons.database import create_engine
Traceback (most recent call last):
File “c:\web\Python25\Scripts\paster-script.py”, line 8, in
load_entry_point(’pastescript==1.3.6dev-r6755′, ‘console_scripts’, ‘paster’)
()
File “c:\web\python25\lib\site-packages\pastescript-1.3.6dev_r6755-py2.5.egg\p
aste\script\command.py”, line 78, in run
invoke(command, command_name, options, args[1:])
File “c:\web\python25\lib\site-packages\pastescript-1.3.6dev_r6755-py2.5.egg\p
aste\script\command.py”, line 117, in invoke
exit_code = runner.run(args)
File “c:\web\python25\lib\site-packages\pastescript-1.3.6dev_r6755-py2.5.egg\p
aste\script\appinstall.py”, line 68, in run
return super(AbstractInstallCommand, self).run(new_args)
File “c:\web\python25\lib\site-packages\pastescript-1.3.6dev_r6755-py2.5.egg\p
aste\script\command.py”, line 212, in run
result = self.command()
File “c:\web\python25\lib\site-packages\pastescript-1.3.6dev_r6755-py2.5.egg\p
aste\script\appinstall.py”, line 456, in command
self, config_file, section, self.sysconfig_install_vars(installer))
File “c:\web\python25\lib\site-packages\pastescript-1.3.6dev_r6755-py2.5.egg\p
aste\script\appinstall.py”, line 583, in setup_config
mod = import_string.try_import_module(mod_name)
File “c:\web\python25\lib\site-packages\paste-1.4-py2.5.egg\paste\util\import_
string.py”, line 81, in try_import_module
return import_module(module_name)
File “c:\web\python25\lib\site-packages\paste-1.4-py2.5.egg\paste\util\import_
string.py”, line 67, in import_module
mod = __import__(s)
File “c:\web\Python25\phones\phones\websetup.py”, line 8, in
import phones.models as model
ImportError: No module named models
все сделал по примеру
в каком *.py должен лежать модуль “phones.models”?
еще одна была заморочка при установке: я думал sqlalchemy идет в комплекте с pylons, поэтому доставлял его потом отдельно командой
“python.exe ez_setup.py SQLAlchemy==0.3.10″
Интересное замечание от Paster-а: “DeprecationWarning: pylons.database
is deprecated, and will be removed from a future version of Pylons. SQLAlchemy
users are recommended to migrate to SAContext” – гибкость модульности в действии
в каталоге phones есть католог models. его можно использовать как пакет. для єтг надо модели описать в нем в файле __init__.py
тогда можно будет импортировать phones.models
более тесная интеграция это зачасту положительно.
Зависит от трафика между модулями, и от того как сам подойдешь к архитектуре
Ошибка была и со вставленным кодом
в “c:\web\Python25\phones\phones\model\__init__.py”:
from sqlalchemy import *
from sqlalchemy.ext.assignmapper import assign_mapper
from pylons.database import create_engine
from pylons.database import session_context as ctx
meta = MetaData()
persons_table = Table(’persons’, meta,
Column(’id’, Integer, primary_key=True),
Column(’name’, String(40)),
Column(’department’, Integer, ForeignKey(’departments.id’)),
Column(’email’, String(40)),
Column(’phone’, String(16)),
Column(’phone_int’, String(6))
)
contacts_table = Table(’contacts’, meta,
Column(’id’, Integer, primary_key=True),
Column(’type’, Integer),
Column(’contact’, String(40)),
Column(’person_id’, Integer, ForeignKey(’persons.id’))
)
departments_table = Table(’departments’, meta,
Column(’id’, Integer, primary_key=True),
Column(’name’, String(40))
)
class Person(object):
def __str__(self):
return “%s [%s]” % (self.name, self.department)
class Contact(object):
def __str__(self):
return self.contact
contact_mapper = assign_mapper(ctx, Contact, contacts_table)
person_mapper = assign_mapper(ctx, Person, persons_table, properties={’contacts’:relation(Contact)})
В общем, ошибка “ImportError: No module named models” возникает на pylons-0.9.6rc2-py2.5. на pylons-0.9.5 без проблем.
а… я не следил. видать что-то поменяли
phones.models нужно исправить на phones.model
у меня другие грабли:
Error Traceback
clear this
clear this
Module phones.controllers.phone:14 in index
> c.persons = Person.select()
exceptions.TypeError: unbound method select() must be called with Person instance as first argument (got nothing instead)