12 марта 2010 в 00:05

Pylons Framework

Расскажу я вам, дорогие мои читатели, о замечательном веб-фреймворке Pylons (язык Python). Непонятно почему он был так обделен вниманием на хабре. Постараюсь исправить такую несправедливость. Я считаю его лучшим и попытаюсь вам раскрыть многие его прелести.


Pylons создавался с оглядкой на популярные решения, так говорит нам wiki. Но по личному опыту скажу вам, что основные идеи были взяты из Ruby On Rails и улучшены!


Pylons активно использует внешние компоненты:



Работа с моделью


Практиковал только алхимию, по этому про неё и примеры.


Опишем нашу модель:


# Создадим Машу
user = User(name=u"Маша")
user.password = sha1("12345").hexdigest()
session.add(user)

# найдем Машу
masha = session.query(User).filter_by(name=u"Маша").first()
# Создадим пост
post = BlogPost(title=u"Мой первый пост", body="Я люблю печеньки",user = masha)
# добавим ключевое слово
post.keywords.append(Keyword(keyword='cookies'))
# удалим Машу
session.delete(masha)
# удалим всех, кто начинается на букву А, используя "продвинутую" алхимию
tUser = User.__table__
session.execute(tUser.delete().where(tUser.c.name.like(u'A%')))

Маршрутизация


Routes точная копия рельсового аналога. За исключением работы с поддоменами. Хотя я уверен это скоро появится и в других фреймворках.


Пример настройки маршрутов:


# именование
map.connect("user_info", "/users/:name/info", controller="account", action="info")

# submappers и префикс
with map.submapper(controller="blog", path_prefix="/blog/") as blog:
    # использование regexp
    blog.connect(R"{id:\d+}", action="show")
    # REST-стиль
    blog.connect("create", action="create", conditions=dict(method=["POST"]))
    blog.connect("update", action="update", conditions=dict(method=["PUT"]))

Используем:


url_for("user_info", name="vlad") => "/users/vlad/info"
url_for(controller="blog", action="show", id="5") => "/blog/5"

P.S.
Про шаблоны сказать особо нечего, рельсовая философия – писать питон код в них можно, хотя и не стоит, но для тестов удобно. А вот формы это другое дело, но это в следующий раз.


Спасибо за внимание.

Илья Чистяков @NElias
карма
12,0
рейтинг 0,0
Full-stack Developer
Похожие публикации
Самое читаемое Разработка

Комментарии (50)

  • +5
    Только по тегам понял, на каком языке этот фреймворк (хоть и догадывался по названию, но указывать язык надо).
    • –1
      Аналогично, прежде чем не читать (ну не входит питон (не орите на меня, я знаю, что правильно — пайтон) в круг интересов) пришлось промотать до тэгов.

      Хорошо бы автору вынести Python в название.
  • +1
    > основные идеи были взяты из Ruby On Rails и улучшены!

    Неплохо бы раскрыть эту фразу детальней…
    • 0
      Цель статьи была не сравнить фреймворки. Для этого нужна отдельная статья которую планирую написать и сравню в ней Django, Pylons и RoR. На вскидку могу лишь заметить, что в Pylons нет соглашений, все указывается явно.
      • 0
        Взяли и выкинули основную идеологическую концепцию рельсов и утверждаете что это улучшение? :) Странно. Я бы сказал более нейтрально: «взяли основные идеи RoR и питонифицировали».
        • 0
          Конечно это моё личное мнение, основанное на любви к питону :) Но вообще SQLAlchemy мне больше нравится, чем ActiveRecord. Routes тоже чуть получше(работа с поддоменами). И шаблоны тоже… вообщем долгая история :)
          • 0
            Мне тоже кажется, что тут больше любви к питону как у меня больше к руби :)
            Например, мне
            User.find(:first, :conditions => {:name => «Маша'})

            понятнее, чем
            session.query(User).filter_by(name=u»Маша").first()

            С ассоциациями то же — belongs_to и has_many это просто супер: как читается, то и означает.
            Найти бы кого-то непредвзятого… :)
            • +1
              Ассоациации? Алхимия это сложная наука, по этому придумали Эликсир! Употребляешь и все становится проще :)
            • 0
              А толку-то с непредвзятого? Это ведь субъективная штука, непредвзятый станет предвзятым, как только ознакомится с обоими подходами :).

              Разве что, ему может не понравится то, что в :conditions надо писать практически raw sql.
            • 0
              >понятнее, чем…

              Тут соверешенно дело не в понятности. Первое паттерн собственно ActiveRecord, второе паттерн DataMapper + UnitOfWork (очень на жавский Hibernate похоже). Каждый из паттернов имеет свои плюсы и минусы, подробнее читайте у Фаулера.

              • 0
                да, но в руби DataMapper тоже свой есть, тем не менее и он более удобочитаемый, чем
                session.query(User).filter_by(name=u»Маша").first()
                :
                zoo = Zoo.first(:name => 'Luke')
                • +1
                  Нет! Библиотека DataMapper реализует паттерн ActiveRecord, так же как и собственно ActiveRecord. Это путаница в названиях. В рубийном DataMapper есть одно важное отличие от ActiveRecord (библиотеки) — он использует еще и решение IdentityMap.

                  martinfowler.com/eaaCatalog/activeRecord.html
                  martinfowler.com/eaaCatalog/dataMapper.html
                  martinfowler.com/eaaCatalog/unitOfWork.html
                  martinfowler.com/eaaCatalog/identityMap.html

                  Если лень читать фаулера, то могу вкратце набросать: в паттерне activerecord модель знает о том как себя сохранять, а класс является еще и фабрикой своих экземпляров. Однако есть проблема — невозможно тестировать/использовать модель без бд, т.е. нету «Persistence Ignorance». Решение DataMapper позволяет обойти это ограничение, однако оно существенно сложнее. Так что дело совсем не в читаемости.

                  Мне самому больше нравится решение ActiveRecord, оно проще, а проблему с тестированием легко можно решить с фикстурами. Но для реализации сложно бизнес логики все же лучше реализации DataMapper, такие как алхимия или хибернейт.
                  • 0
                    Фаулера читать не лень :), в заблуждения вводят названия фреймворков (например, когда-то я думал, что ActiveRecord — это чисто название фреймворка, а не название паттерна изначально).
                    Пока ехал в метро, понял что session — это и есть UnitOfWork, а заодно и закрались сомнения относительно рубишного ДатаМаппера.
                    Спасибо за короткий анализ, у Фаулера его нет.
                    Может знаете, есть ли на руби правильная реализация ДатаМаппера?
                    • 0
                      На сколько знаю, «правильной» реализации DataMapper на руби нету. Хотя для простых случаев он и не нужен, а для более сложных я бы выбрал java с hibernate.
  • 0
    Действительно, схожесть с RoR увидел только в роутах…
    • 0
      А сравните с ASP и c RoR, кто ближе?
      • 0
        ASP это вообще совсем «не то». ASP это компонетный statefull фреймворк, а всякие Pylons и RoR это request/response-based и stateless.
        • 0
          Вот! ASP это фреймворк для WEB и RoR для WEB. Если вы берете классификацию по назначению, то оба они попали в одну корзину, а VCL скажем в другую. Если вы классифицируете по стэйтлесс и стэйтфул. То группировка изменится. Состояние в Django есть — это сессия и много еще разных моментов. В ASP я писал наследника от HTTP кто, то там (не помню уже), потом в массиве хранил пути и обработчике путей. При этом конечно 90% ASP было выкинуто к чертям, но это был RoR (точнее Django стиль).

          Возможно я коряво излагаю свою мысль, но Django, Pylons, TG это все близкие родственники RoR. В противоположность разным WSGI фреймворкам которые работают на более низком уровне (ДА Я ЗНАЮ, что Django WSGI, но до такого уровня обычно никто не опускается). В этих фреймворках можно создать роуты, а можно обойтись вообще без них.
          • 0
            >Состояние в Django есть — это сессия и много еще разных моментов

            Ну сессии как бы везде есть. Говоря stateless или statefull я конечно же имел ввиду принцип построения визуальных компонентов. Т.е. используют ли компоненты активно сессии или нет. Хотя мир не черно-белый и в RoR есть такая штука, как flash, некое подобие компоненты с состоянием…
            • 0
              flash есть в Pylons
              • 0
                flash есть в большинстве фреймворков (и даже в некоторых CMF).

                Задача после post формы выдать сообщение об её обработке после стандартного редиректа слишком частая, чтобы кто-либо мог её проигнорировать.
    • 0
      Или с типичным PHP проектом, где роутами занимается апач, а весь код в шаблоне
      • +2
        Да ладно! В типичном пхп-проекте апач кидает запросы на индекс.пхп, а тот уже дальше — в зависимости от архитектуры.
    • +1
      Ещё WebHelpers утащили оттуда. И мне очень помогает библиотека Pytils, который подглядели у Rutils оттуда же :-)
  • 0
    Интересный фреймворк, периодически поглядываю на него, но есть пара проектов на django, а вот что-то написать с использованием pylons как-то руки не доходят…
  • 0
    Расскажите для тех, кто не на рельсах, что за маршруты и чем они хороши.
    • 0
      Способ описания связи урлов и «ушей» приложения. Помощней, чем джанговская url.py, т.к. можно управлять маршрутом в зависимости от метода запроса, например. + (если всё как в РоР) можно создавать REST-маршруты «в одну строчку». В кратце так, наверное.
    • 0
      Урл-маршрутизация — разбор адресов, по которым обращается клиент и в зависимоти от них выполнение различных контроллеров (суть функций).
      Так, например, в моём приложении, набрав www.example.com/order/5 можно увидеть заявку №5, а на www.example.com/orders можно увидеть весь список заявок. А на www.example.com/order/5/edit у меня скрывается форма редактирования заяки. Ну и так далее :-)
      И этим у меня заведуют следующие строчки в routing.py (первая — не в тему):
      map.connect ("startpage", "/", controller="main", action="index")
      map.connect ("orderlist", "/orders", controller="order", action="list")
      # Заявки
      map.connect ("order", "/order/{id}", controller="order", action="view", requirements = {'id': '\d+'})
      map.connect (None, "/order/{id}/{action}", controller="order", requirements = {'id': '\d+'})
      

  • +1
    Ах, как коротко-то…
    Скажу я — фреймворк хорош. Вот только, в отличие от RoR (как я понял) — в полстрочки здесь ничего не пишется. Программисту под контроль изначально отдаётся больше вещей.
    И модульность здесь поставили во главу угла изначально, поэтому начинка может отличаться и изменяться. С одной стороны хорошо, а с другой — не очень.
    Для заинтересовавшихся есть руководство (на английском): Pylons Book. Там всё расписано (хотя часть информации уже могла устареть и устарела)

    Замечание автору: в версии 1.0 фреймворка (а точнее в последней версии Routes) функцию url_for объявили устаревшей и выкинули к чертям. Следует использовать функцию url импортируемую из pylons. Синтаксис аналогичен, начинка и поведение — отличаются.
  • 0
    использую этот фреймворк в нескольких своих проектах.
    В отличии от django позволяет использовать какой угодно ORM, какой угодно template engine, чем меня и привлёк.

    и актуальная документация на ближайший релиз 1.0 уже имеется
    • +1
      С каких это пор джанга запрещает использовать сторонний шаблонизатор и ОРМ?
      • 0
        Да собственно никто не запрещает, с шаблонами просто, а вот ORM… весь contrib идет лесом, хотя можно и одновременно использовать разные ORM. Вообще не суть, у Django просто философия другая. Хотя Pylons с FormAlchemy уже рядом моячет по функциональности.
      • 0
        может быть я отстал от жизни, но, насколько я помню, в джанге отвязать родной ORM и привязать SQLAlchemy было невыполнимой задачей. Неужели уже эта задача выполнима?
        • 0
          Еще как выполнима. Кто вам мешает вместо:
          class Model(models.Model):
          ...blah...

          писать
          class Model(Base):
          ...blah...

          ?

          Отвалятся контрибы многие, но они не есть часть джанги.
          • 0
            Отвалятся не только contrib, а ещё всякие хорошие расширения. А без этого Django уже теряет все свои прелести быстрой разработки.
            • 0
              Никто не говорил, что будет легко.

              Но меж тем, джанга будет работать.
              • 0
                ну так а смысл тогда, если не будет легко? :)

                перефразирую — «задача смены ORM выполнима, но в этом случае Djangо теряет все свои преимущества».
                • +1
                  Есть мнение, что в этом случае получится как раз Pylons :)
      • +2
        из того, что написано в pylonsbook, можно сделать вывод, что разница в использовании других компонентов в Django и в Pylons всё-таки есть:

        Слабое связывание и чистое разделение
        — Веб-фрэймворки, такие как Django и Ruby on Rails стали крайне популярными в последние годы, потому что они обеспечивают структуру, позволяющую быстро создавать хорошие веб-сайты, определяя, то как структурированы данные.

        Предоставляемые инструменты работы с данными могут как автоматически создавать код (scaffold в случае Ruby on Rails), так и создавать интерфейсы форм при запуске (в случае с Django).

        Хотя эти фрэймворки поддерживают чистое разделение между кодом моделей, видов и контроллеров, они не такие слабосвязанные как в Pylons, потому что работоспособность приложения как единого целого во многом полагается на соединяющий код, находящийся в фрэймворке. Легко создать простое приложение при помощи этих фрэймворков, но настройка их поведения позднее может быть сложной, потому что это предполагает понимание того, как работает код предоставляемый фрэймворком, перед тем как вы поменяете его поведение. Чтобы было проще использовать фрэймворк, его код часто достаточно сложен, и в результате настройка может быть трудной.

        Pylons более слабосвязанный. Поскольку он не предоставляет инструментов для автоматической генерации почти законченного сайта из определения модели, ему не нужен сложный соединяющий код, удерживающий всё вместе. Вместо этого, он предоставляет низкоуровневые API и методологии, позволяющие быстро и просто соединить вместе компоненты, которые вы сами выбираете.

        Такой подход к слабому связыванию не означает, что вам нужно создавать код для всех частей. В соглашении по конфигурации Pylons считается, что вы захотите использовать стандартные настройки при создании нового проекта. Их можно легко изменить. Например, по умолчанию Pylons использует фрэймворк для работы с шаблонами Mako для генерации шаблонов из видов, но вы не обязаны его использовать. Вы легко можете использовать любой из других крупных языков шаблонов Python, включая Genshi, Jinja или даже Tal или Breve.
    • 0
      Тогда можно и bottle.py использовать.
  • 0
    Для SQLAlchemy есть неплохая надстройка Elixir
  • 0
    в порядке информации к размышлению, а не приглашения к холивару.

    имхо, pylons очень мощный и гибкий, но достаточно монстрообразный фреймворк, особенно для небольших проектов. и в этом смысле, напоминает symfony.

    думаю, джанга в этом смысле предпочтительнее и даже быстрее.
    кроме того, в pylons нельзя использовать raw sql запросы, что иногда создает большие трудности.
    по крайней мере, не удалось быстро найти как их использовать.

    • 0
      в pylons нельзя использовать raw sql запросы, что иногда создает большие трудности.

      а каким боком тут pylons? он не предоставляет DBLayer сам по себе. и вас никто не заставляет пользоваться SQLAlchemy, можно использовать и прямое подключение к БД
      • 0
        можно. но это уже не гламурно будет
        • 0
          почему же это «негламурно»? далеко не всем нужен вообще ORM, поэтому использование SQLAlchemy или любого другого ORM — опционально.

          django — скорей подходит под определение «монстрообразный фреймворк» :)
    • 0
      пример raw:
      >>> from sqlalchemy.sql import text
      >>> s = text("""SELECT users.fullname || ', ' || addresses.email_address AS title
      ...            FROM users, addresses
      ...            WHERE users.id = addresses.user_id AND users.name BETWEEN :x AND :y AND
      ...            (addresses.email_address LIKE :e1 OR addresses.email_address LIKE :e2)
      ...        """)
      sql>>> print conn.execute(s, x='m', y='z', e1='%@aol.com', e2='%@msn.com').fetchall()
      

      Но чаще такое не нужно, это все можно методами описать.
      Подробнее про sqlexpression.
      • 0
        спасибо. именно то, что нужно.

        а подскажите еще, пожалуйста, как решается в ORM пробелма с операторами аггрегации?
        типа group by
        в свое время искал, но так ничего и не нашел.
        • 0
          Подсказываю.
          ORM:
          >>>session.query(User.name).group_by(User.name).count()  
          SELECT count(1) AS count_1 FROM (SELECT users.name AS users_name FROM users GROUP BY users.name) AS anon_1 ()
          

          SQLExpression:
          >>> s = select([addresses.c.email_address, addresses.c.id]).distinct().\
          ...     order_by(addresses.c.email_address.desc(), addresses.c.id)
          >>> conn.execute(s).fetchall() 
          SELECT DISTINCT addresses.email_address, addresses.id FROM addresses ORDER BY addresses.email_address DESC, addresses.id ()
          
          • 0
            супер. спасибо.
    • +1
      кстати, начиная с SQLAlchemy 0.6 — вполне возможно использовать raw sql и маппить его:

      >>> session.query(User).from_statement(«SELECT * FROM users where name=:name»).params(name='ed').all()
      [<User('ed','Ed Jones', 'f8s7ccs')>]

      www.sqlalchemy.org/docs/ormtutorial.html#using-literal-sql

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Интересные публикации