×Закрыть

Пробуем 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 мы можем любоваться нашим приложением во всей его красе.

LinkedIn

8 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

у пайлонса свой собственный вебсервер paster... он с апачем ни как не взаимодействует и не зависит от него

проблема с апачом, попробовал хелло ворлд, а изменения видно только если запускать paster serve —reload development.ini... где и как апач может кэшировать данные?

В каком смысле меняете модель? Изменяете поля и т.д.?

Ну, в общем, да. Ситуация такая: я создал модель, запустил «paster setup-app...». Затем поменял в модели структуру: например, добавил одну колонку и изменил другую. «paster setup-app...» не дает никакого эффекта — в базе остается старая структура. То есть никакого «alter table...» не происходит.

В каком смысле меняете модель? Изменяете поля и т.д.? Тогда надо сделать следующее:

$ paster setup-app development.ini

Для простоты отображения данных, я немного до-обработал модель данных для нашей задачи.

А модель данных отобразилась каким-то образом в базе? у меня что-то не получилось...Меняю модель — реально в базе ничего не меняется.

вот бы в приведенном коде выделять добавленные строчки! а то «ля этого необходимо подправить файл config/routing.py, добавив туда одну строчку, чтобы файл выглядел следующим образом» и непонятно какую добавили. утрирую конечно с примером., но все же.

да было бы неплохо. попробую так сделать.

вот бы в приведенном коде выделять добавленные строчки! а то «ля этого необходимо подправить файл config/routing.py, добавив туда одну строчку, чтобы файл выглядел следующим образом» и непонятно какую добавили. утрирую конечно с примером., но все же.

Подписаться на комментарии