Pull to refresh

Comments 28

Ну что же — пока всё хорошо, но маловато. Пишите еще :)
Больше велосипедов, и чем квадратнее колёса, тем лучше!
Пожалуй, слишком саркастично получилось. Лучше спрошу безо всякого сарказма: а почему не Flask, например?
Если продолжать логическую цепочку, то видимо можно дойти до вопросов, почему не PHP, почему не Perl, почему не… впрочем, не будем пока об извращениях. Очень много хороших вещей не появилось бы на свет, если бы их авторы изначально были демотивированы мыслью о велосипедах (причём несовершенных в первых реализациях — первый блин, как известно).
Разумеется, есть именитые профессионалы, которые с первой попытки создают эпичные вещи, о которых позже слагают легенды, но есть и новички, в которых изначально мало кто верит, но потом вырастают вместе со своими проектами.
Мне кажется, было бы конструктивней, если бы Вы немного расшифровали свою оценку «квадратности колёс» — кто знает, возможно, дадите новому проекту более подходящее направление и поможете избежать неочевидных автору граблей.
По-моему, ошибка (очевидная) тут прямо в заголовке. Ну или в постановке задачи, если хотите. Как так — Django своими руками, для чего? Flask (джангоподобный фреймворк, который не накладывает ограничений на применяемые батарейки) существует давно и успешно.

Ни одного камня в его сторону не полетело, а ведь в рамках статьи явственно видна попытка сделать то же самое. Вот и получается, что это всего лишь попытка исправить пресловутый фатальный недостаток.

В веб-разработке на Python есть два основных лагеря. В первом любят монолитный код и Django, а вторые стараются переехать с Pylons и Repoze/BFG на Pyramid. Есть ещё разные кучки анархистов с микрофреймворками, но бурного развития там никогда не было.

Так вот. Фреймворк из статьи целиком и полностью покрывается функциональностью Pyramid, в котором модульность компонентов носит характер сектантского культа. Благодаря этому, даже в рамках одного проекта, разработчику дозволяется пользоваться сразу несколькими шаблонными движками. И Jinja2 в этом списке, естественно, присутствует.

Возможно в следующих статьях вы разовьёте идею своего фреймворка в какую-то уникальную и практичную идею, но пока это просто разминочные упражнения для отдельно взятого программиста.
Pyramid очень крутая штука, но концептуально очень сложная. Но очень крутая.

Я по ней даже планировал написать пару статей, но в итоге отказался, поскольку слишком много возможностей получается, по сути не статьи получаются, а реклама конкретного подхода к реализации проекта на pyramid.
В нём не так много изменений по сравнению с Pylons. Там уже были заложены принципы построения «фреймворка в виде клея» между сторонними пакетами. Это самая сложная концептуальная часть. Если до этого вы работали с Pylons, то разобраться во внутренностях Pyramid — дело одной недели. Рефакторинг-миграция с Pylons 1.0 на Pyramid 1.3 у меня заняла примерно такое количество времени.

Основательно, в Pyramid решили всего три главные проблемы:
1. Избавились от paste.registry.StackedObjectProxy в пользовательском коде, который эмулировал потокобезопасные локальные глобальные переменные. Пользовательские контроллеры теперь стали больше походить на джанговские, когда весь контекст запроса хранится в виде аттрибутов объекта request. Это существенно упростило процесс написания функциональных тестов.

2. Избавились от необходимости наследовать BaseController для всех пользовательских контроллеров, что позволило проще комбинировать модули внутри отдельно взятого проекта.

3. Полностью перешли на pkg_resources и систему сигналов для внедрения сторонних плагинов. Раньше (в Pylons), для подключения плагинов использовались WSGI Middleware, которые просто добавляли новые слои логики поверх вашего веб-приложения. Это было не очень гибко и подходило не для всех плагинов. Теперь подобных проблем практически нет.

Этого оказалось достаточно, чтобы решить почти все трудности, возникавшие при разработке на Pylons.

Все остальные части фреймворка — это кодовая база Repoze/BFG и их небольшое наследие от Zope (ZCML и Traverse), которые совершенно не обязательно использовать в своих проектах.
От pylons там ОЧЕНЬ много отличий, вот от repoze.bfg мало. По сути разработка на pylons сводилась к использованию «глобальных» переменных. А тут резко всё обрубили, причём настолько, что прямая миграция сложного проекта становится очень сложной — мне не очень нравится официально предложенные подход миграции с pylons в виде реализации слоя эмуляции пилоновских граблей. Опять же совершенно адовая аутентификация с авторизацией. Pylons был существенно проще. Но архитектурно pyramid гораздо стройнее, хотя и сложнее.

Миграция довольно простая.
1. Сначала, оставаясь на Pylons, проведите рефакторинг своего кода, где глобальные переменные config, url, session, response, tmpl_context биндятся к объекту request в самом начале запроса (это можно сделать в BaseController) и используются в коде через request.config, request.url и т.д. Другими словами — локализуйте контекст в одном объекте.
2. Переопределите семантику вызова методов из pylons.controllers.core.WSGIControllerBaseController таким образом, чтобы каждый пользовательский контроллер получал объект request в виде обязательного первого аргумента. Просто унаследуйте этот класс и переопределите метод _perform_call:
    def _perform_call(self, func, args):
        """Hide the traceback for everything above this method"""
        # Unused variable
        #__traceback_hide__ = 'before_and_this'
        # Inject request object here in order to emulate Pyramid view
        # callable in controllers
        req = self._py_object.request
        return func(req, **args)

Теперь вы практически полностью эмулируете API простого view callable из Pyramid.
3. Замените все вызовы request.url(...) на request.route_path(...), а request.url(..., qualified=True) на request.route_url(...).
4. Замените request.config на request.registry.
5. После этого, создайте репозиторий с pyramid_sqla приложением, и влейте в него весь код от проекта на pylons.
6. Настройте простой контроллер в Pyramid, убедитесь что он работает, после чего начинайте итеративно рефакторить каждый контроллер из pylons. Рефакторинг заключается в переносе кода контроллера и кода из Routes в систему роутинга Pyramid.

Таким способом, я итеративно, без особых проблем перевёл проект с 20К+ строк кода на Pylons в Pyramid за одну неделю (календарную).
UFO just landed and posted this here
Так не надо:

'/app/' + module +'/templ/'


Лучше так:

module.join(("/app/", "/templ/"))


А лучше всего так:

import os
os.path.join("app", module, "templ")
Второй код, что я привёл, будет работать некорректно, когда будет больше вложенных директорий (>2).
...
i = t.index(':')
module = t[:i]
module_path = '/app/' + module +'/templ/'
file = t[(i+1):]
...


Можно проще:

module, file = t.split(":")
Если проще, то так

module, file = t.split(":", 1)
Да, благодарю, исправил, имела место быть недоработка. :)
я бы спрашивал путь у самого модуля, предварительно его заимпортировав, module.__file__, так будет меньше зависимость от структуры проекта (может захочется устанавливать модули как обычные питоновские пакеты в будущем).
Примерно так:

import os, sys

def get_app_root(app):
    """Returns path to app or app name."""
    if isinstance(app, (str, )):
        __import__(app)
        app = sys.modules[app]
    return os.path.dirname(os.path.abspath(app.__file__))

tpl_path = os.path.join(get_app_root(module), 'templ')
Добавил, согласен это более универсально. Только придется писать имя модуля полностью. Но это, думаю, и к лучшему.
Куча вариаций расширений под которыми читаются файлы с шаблонами — это совсем не python way.
Чтобы не изобретать велосипед по поиску шаблонов в каталогах есть класс FileSystemLoader в Жинже.
И вообще, код для публикации в статьях наверное стоит оформлять по стандартам pep8, а то ведь его накопипастят себе разные люди и будут думать что он со всех сторон верный.
Каждый раз, когда вы добавляете что-то в __builtin__, рождается ещё один PHPшник.
Секрет популярности PHP раскрыт? :))
Предлагаете импортировать везде функцию, которая гарантированно нужна во всем проекте?
Если функция load_template ничего не найдет, то она зачем-то вернет строку из одного пробела. Которая приведется к True, а не к False, как, видимо, ожидал автор.

Рекомендуется к прочтению.
Что-то не с того конца начат веб фреймворк. Я бы начал все таки с приложения wsgi и маршрутизации запросов. Почему — в общем случае, особенно в сегодняшних реалиях, вы можете и не рендерить никакого HTML вообще, отдавая только JSON. А вот не работать с HTTP веб фреймворку будет сложновато.
Я думал об этом. Но просто описать настройку wsgi файлика не интересно таких материалов хватает. Интересно было бы описать вывод сообщений об ошибках, наподобие того как это делается в Werkzeug или Django, но было решено в последующих материалах на этом остановится.
Я имел в виду wsgi приложение, а не wsgi файлик.
Sign up to leave a comment.

Articles