Пробуем Pylons, часть 2: views
Современный web-development (и не только) просто изобилует всякими модными сокращениями, от множества всяких CRUD, ReST, SOAP, KISS, BRTG, TiMO и так далее. Не последнее место среди всей этой мешанины занимает аббревиатура MVC.
Сейчас даже начинающий программист (если он себя уважает), знает что объединять код и представление — очень плохо. Ну а язык, поощряющий такой подход «by design» — это, соответственно, плохой язык.
Поскольку Python — язык хороший, а Pylons — замечательный Фреймворк, написанный на хорошем языке, то позволить себе такой ужас как генерацию HTML из кода скрипта, он себе явно позволить не может. Это во-первых не модно, во-вторых и неудобно... Представьте себе ужас дизайнера, когда он увидит свой HTML код внутри каких-то странных скриптов, или отвращение программиста, вынужденного загонять многие килобайты кода странички в свой исходник. Вот для исправления этой ситуации и были разработаны так называемые «шаблонные движки» (template engines).
По своей сути, шаблонный движок (или шаблонизатор, тут как всегда трудности перевода), просто-напросто берет текстовый файл, называемый шаблоном, и проводит с ним некие операции. Самая простая операция, например, подстановка значения некой переменной, переданной «снаружи» вызываемым скриптом. Более сложные операции включают в себя проверки условий, выполнения циклов, наследование шаблонов и т.п.
На Python подобных шаблонизаторов написано уже весьма и весьма много. К радости следует отметить, что Pylons поддерживает многие из них сразу, а большинство остальных — через механизм buffet.
Рассмотрению достоинств и недостатков отдельных шаблонных движков можно посвятить целую статью (если будут желающие, я могу за нее взяться), но для Pylons проектов по-умолчанию выбраны шаблоны от Mygthy.
Для начала экспериментов, нам необходимо создать контроллер, который будет управлять нашим приложением-телефонной книгой. Для этого выполним следующую команду:
$paster controller phoneЭта команда, во-первых создаст в каталоге controllers файл phone.py, в котором мы будем размещать текст управляющего контроллера, во-вторых создаст заготовку для функционального теста в каталоге tests/functional. На тестировании я пока тоже фокусироваться не буду, это — тема для отдельной статьи.
Следующее что надо сделать — это подключить наш контроллер и задействовать его в роутинге для сайта.
Для этого необходимо подправить файл config/routing.py, добавив туда одну строчку, чтобы файл выглядел следующим образом:
import os from routes import Mapper def make_map(global_conf={}, app_conf={}): root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) map = Mapper(directory=os.path.join(root_path, 'controllers')) map.connect('error/:action/:id', controller='error') # добавляем новый контроллер map.connect(':controller/:action/:id', controller='phone', action='index', id=0) map.connect('*url', controller='template', action='view') return mapДля простоты отображения данных, я немного до-обработал модель данных для нашей задачи. Теперь она выглядит так:
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 class Department(object): def __str__(self): return self.name contact_mapper = assign_mapper(ctx, Contact, contacts_table) department_mapper = assign_mapper(ctx, Department, departments_table) person_mapper = assign_mapper(ctx, Person, persons_table, properties={'contacts':relation(Contact), 'dep':relation(Department)})Как видно, я добавил отображение для таблицы подразделений и соответствующую связь в таблице персон (хочу заметить что это еще далеко не последнее изменение).
Теперь можно с чистой совестью заняться кодированием отображения данных.
Для этого напишем текст нашего первого контроллера в файле controllers/phone.py
Он очень прост:
from phones.lib.base import * from phones.models import Person class PhoneController(BaseController): def index(self, id): # выбираем данные c.persons = Person.select() # возвращаем отрендереный шаблон return render_response('list.myt')Для начала, он просто выбирает всех персон, занесенных в телефонную книгу и возвращает ответ путем рендеринга шаблона list.myt.
Осталось только этот самый шаблон создать. Он также в принципе несложен. Создайте в каталоге templates вашего проекта файл list.myt следующего содержания:
<h1 class="main">Title List</h1> <ul id="titles"> % for person in c.persons: <li> <% person.name %> <% person.dep %> % for contact in person.contacts: <% contact %> % #end for </li> % #end for </ul>Он просто выводит в виде списка имена людей и подразделения в которых они работают, а при наличии дополнительных контактов выводит и их.
В нем не хватает очень многого, например, проверки наличия дополнительных контактов, нормального форматирования, пристойного внешнего вида и т.д., но ведь не все так сразу. Я думаю многие хотят уже скорее увидеть все это в действии. Нет ничего проще:
$paster serve --reload development.ini
После этого, по адресу 127.0.0.1:5000/phone мы можем любоваться нашим приложением во всей его красе.
8 коментарів
Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.