Тьяго Авелино. Bottle - полный веб-стек без Django, 2014

Перевод статьи: Bottle, full stack without Django

Автор: Тьяго Авелино (Thiago Avelino)

Эта заметка в блоге основана на лекции, которую я прочитал здесь, в Бразилии. Посмотрите слайды!

1. Веб-микрофреймворк Bottle

Bottle - это веб-микрофреймворк, совместимый с WSGI, который зависит только от стандартной библиотеки Python и совместим с Python версий 2.6, 2.7, 3.2, 3.3 и 3.4. Весь исходный текст фреймворка умещается в одном файле. Он был создан Марселем Хеллкэмпом (Marcel Hellkamp - @defnull) и поддерживается сообществом, образовавшимся вокруг этого фреймворка.

Django - это прагматичный фреймворк для быстрой веб-разработки, который написан на Python, использует стандарт MTV (model-template-view - модель-шаблон-представление). Изначально он был создан как система для управления сайтом журнала в городе Лоуренс, в Канзасе. Стал проектом с открытым исходным кодом, был опубликован под лицензией BSD в 2005 году. Название Django фреймворк получил в честь джазового музыканта Джанго Рейнхардта. Django стал очень известен благодаря поставке с "батарейкам", то есть благодаря нескольким библиотекам, добавленным к основному коду фреймворка для упрощения разработки. Вместе с фреймворком эти библиотеки сформировали так называемый "полный стек".

Прагматичный - значит ориентированный на решение практических, реальных задач с чётко определённой целью. Другими словами, команда разработчиков Django приняла некоторые архитектурные решения, а пользователи Django следуют этой архитектуре, не имея возможности легко её поменять.

Хорошо ли, если вместе с веб-фреймворком поставляются "батарейки"? Если вы согласны использовать всё, что даёт вам фреймворк, то ответ - да. Однако, не все веб-проекты одинаковы.

В большинстве проектов используется не более 80% возможностей Django. В тех случаях, когда используется не более 50% возможностей, мы вынуждены платить за все, что было предусмотрено архитектурой Django. То есть теряем в производительности, потому что в Django имеется множество модулей, которые не используются, но по-прежнему продолжают работать. Когда же мы используем микрофреймворк, мы берём на себя роль архитектора приложения. Поскольку у нас нет предопределённой архитектуры, нам нужно время, чтобы определить архитектуру приложения.

Все пакеты Python, которые имеются в библиотеке Django, в микрофреймворке могут быть заменены!

2. SQLAlchemy

SQLAlchemy существовал до Django (да, до Django) и начиная с 2005 года появилась команда, которая стала заниматься разработкой ORM. Команда же разработчиков Django занимается одновременно и разработкой фреймворка и разработкой ORM. Я думаю, что не стоит говорить о том, что результат работы специалистов обычно бывает лучше, чем результат работы универсалов.

Структура модели:

class Entity(Base):
    __tablename__ = 'entity'
    id = Column(Integer, Sequence('id_seq'), primary_key=True)
    name = Column(String(50))

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return "<Entity('%d', '%s')>" % (self.id, self.name)

3. WTForms

Обходное решение для тех, кто не использует Django и кому нужно работать с формами - это WTForms, которые были созданы в 2008 году и поддержка которых продолжается до сих пор!

Структура формы:

class UserForm(Form):
    name = TextField(validators=[DataRequired(), Length(max=100)])
    email = TextField(validators=[DataRequired(), Length(max=255)])

4. Шаблонизатор

Jinja2 - это современный удобный для дизайнеров язык шаблонизации для Python, который был создан по образцу шаблонов Django. Он быстрый, широко используется и может быть дополнительно защищён изоляцией рабочего окружения.

Структура шаблона:

<title>{% block title %}{% endblock %}</title>
<ul>
{% for user in users %}
  <li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>

5. Миграция

Использование Alembic начинается с создания среды миграции. Это каталог сценариев, которые относятся к отдельному приложению. Среда миграции создаётся единожды, а затем поддерживается совместно с исходным кодом самого приложения.

Структура миграции:

revision = '1975ea83b712'
down_revision = None

from alembic import op
import sqlalchemy as sa

def upgrade():
    pass

def downgrade():
    pass

Как создать обновление и откат:

def upgrade():
    op.create_table(
        'account',
        sa.Column('id', sa.Integer, primary_key=True),
        sa.Column('name', sa.String(50), nullable=False),
        sa.Column('description', sa.Unicode(200)),
    )

def downgrade():
    op.drop_table('account')

Структура модификации таблицы:

"""
$ alembic revision -m "Add a column"
"""

revision = 'ae1027a6acf'
down_revision = '1975ea83b712'

from alembic import op
import sqlalchemy as sa

def upgrade():
    op.add_column('account', sa.Column('last_transaction_date', sa.DateTime))

def downgrade():
    op.drop_column('account', 'last_transaction_date')

6. Заключение

Здесь было продемонстрировано всё, что можно найти в стеке Django. Я писал эту заметку для не для того, чтобы принизить Django. Я лишь показал, что существуют другие полностековые решения для разработки приложений. Многие люди используют Django, не понимая экосистемы Python. В наше время Django предоставляет множество готовых решений, что заставляет некоторых разработчиков лениться и не наращивать мастерство в проектировании архитектуры приложения.

Помогайте Bottle. Мы - растущее сообщество. Чтобы внести свой вклад в код Bottle, обратитесь к списку открытых задач. В случае сомнений можно обратиться в список рассылки или в IRC-канал.

ПРИСОЕДИНЯЙТЕСЬ

7. Примечания переводчика

Считаю, что в статье тема не раскрыта. Не понятно, какая такая особенная архитектура приложения имелась в виду, которая никак не сочетается с Django. Перечислено несколько средств, которые в чём-то заменяют средства, имеющиеся в Django. Без сомнений, SQLAlchemy заткнёт за пояс джанговский ORM. Безусловно, Jinja2 - очень быстрый шаблонизатор, быстрее джанговского. Но стоит иметь в виду, что в Django все эти средства глубоко интегрированы друг с другом.

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

Другой пример - в Django миграции можно сгенерировать автоматически. Автоматическая генерация даже умеет определять переименованные поля. А если же автоматика не сработала корректно, то автоматически сгенерированный код миграции можно подправить и руками.

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

Я сам в своих проектах использую Django, но для некоторых задач он действительно избыточен. Например, в одной из прошлых своих заметок я писал Тайловый сервер на основе Python, Mapnik и Bottle. Денис Рыков, материалами которого я воспользовался, тоже писал тайловый сервер, воспользовавшись фреймворком Bottle. Для себя я решил, что если приложение не работает с собственной базой данных, а берёт информацию из сторонних источников и занимается лишь её преобразованием, или выполняет какие-то действия по требованию, то лучше использовать Bottle, т.к. в нём нет избыточных возможностей, а сам он обладает минимумом зависимостей и работает с любой версией Python.

Написать автору