Недавно рассматривали организационную экосистему Python. В принципе, все всё правильно поняли.
Как точно резюмировал один из читателей: "постмодерн".
Другой читатель, посмотрев на фотографию директора Python Software Foundation, критично (в мой адрес) прокомментировал: "ну, ты бы ещё поставил ей в упрёк, что у неё в интересах «дивёрсити» указано!". Но позвольте, я ведь просто выложил фотографию с подписью, которую человек сам о себе с гордостью демонстрирует, практически, на своём официальном сайте. Мне показался такой упрёк забавным и показательным, я и сам что-то подобное чувствовал при написании текста: иррационально кажется, что прямое дословное цитирование чьих-то пиар ходов одновременно является как бы критикой автора этих ходов. С одной стороны, хорошо бы при пересказе чьей-то позиции по ходу заочной полемики, по возможности, сглаживать острые углы, если человек явно ошибся. Но в случае фирмы, специализирующейся на популяризации самой себя, ошибки в демонстративных жестах никакой быть не может, это целенаправленная самопрезентация.
Хотел дальше по этой линии постов вкратце разобрать список учредителей PSF (в отличие от показанной ранее "исполнительной" части организации, там есть "содержательные" персонажи). Но пока отложим: думаю, надо нам всем ещё поработать над собой, над повышением уровня толерантности и ментального самоконтроля, чтобы от рассмотрения профилей значимых общественных деятелей (самими этими деятелями о себе и написанных) возникала положенная цивилизованному человеку автоматическая улыбка и чувство эмпатии, а не сложная композиция плохо "диверсифицированных" мыслей.
Перескочим сразу на следующую тему (в этой линии тем). JetBrains участвует в кампании по сбору средств на Django (деньги собирает отдельная организация) – отчисляет все поступления с продаж IDE PyCharm в Django Software Foundation. Дело стоящее, давайте в меру сил и доступных средств поучаствуем в популяризации хорошего языка и фреймворка.
Участвовать будем путём критического анализа отдельных аспектов фреймворка и сопутствующей инфраструктуры. Материал будет потихоньку выкладываться.
#programming #django #python
Как точно резюмировал один из читателей: "постмодерн".
Другой читатель, посмотрев на фотографию директора Python Software Foundation, критично (в мой адрес) прокомментировал: "ну, ты бы ещё поставил ей в упрёк, что у неё в интересах «дивёрсити» указано!". Но позвольте, я ведь просто выложил фотографию с подписью, которую человек сам о себе с гордостью демонстрирует, практически, на своём официальном сайте. Мне показался такой упрёк забавным и показательным, я и сам что-то подобное чувствовал при написании текста: иррационально кажется, что прямое дословное цитирование чьих-то пиар ходов одновременно является как бы критикой автора этих ходов. С одной стороны, хорошо бы при пересказе чьей-то позиции по ходу заочной полемики, по возможности, сглаживать острые углы, если человек явно ошибся. Но в случае фирмы, специализирующейся на популяризации самой себя, ошибки в демонстративных жестах никакой быть не может, это целенаправленная самопрезентация.
Хотел дальше по этой линии постов вкратце разобрать список учредителей PSF (в отличие от показанной ранее "исполнительной" части организации, там есть "содержательные" персонажи). Но пока отложим: думаю, надо нам всем ещё поработать над собой, над повышением уровня толерантности и ментального самоконтроля, чтобы от рассмотрения профилей значимых общественных деятелей (самими этими деятелями о себе и написанных) возникала положенная цивилизованному человеку автоматическая улыбка и чувство эмпатии, а не сложная композиция плохо "диверсифицированных" мыслей.
Перескочим сразу на следующую тему (в этой линии тем). JetBrains участвует в кампании по сбору средств на Django (деньги собирает отдельная организация) – отчисляет все поступления с продаж IDE PyCharm в Django Software Foundation. Дело стоящее, давайте в меру сил и доступных средств поучаствуем в популяризации хорошего языка и фреймворка.
Участвовать будем путём критического анализа отдельных аспектов фреймворка и сопутствующей инфраструктуры. Материал будет потихоньку выкладываться.
#programming #django #python
В целом если вы видели один MVC фреймворк, вы видели их все. Переходя с Rails на Django (и наоборот) вы, может быть, ожидаете увидеть какие-то различия, но на самом деле всё в точности то же самое.
Однако при более подробном всматривании и ощупывании всплывает этакий программистский вариант "ложных друзей переводчика". И там, и там есть applications ("приложения"), migrations ("миграции"), views ("представления", здесь перевод не устоявшийся и их обычно "вьюхами" и называют). Но все эти штуки в обоих фреймворках либо существенно отличаются, либо обозначают просто разные вещи.
Вот планирую в небольшом цикле заметок остановиться именно на таких различиях, а сходство больше и не упоминать.
В Django опорный паттерн называется MVT, model-view-template. В Rails он называется MVC, model-view-controller. Разница только терминологическая: то что в Rails называют views (перемешанные фрагменты HTML-кода и управляющих операторов), в Django называют templates. То, что в Rails называют controllers (класс, обрабатывающий запрос) в Django называют views (может быть классом, а может быть отдельной функцией). Здесь достаточно один раз привыкнуть, задать риторический вопрос "зачем надо было всё перемешивать?", и дальше спокойно работать.
В Rails слово application, "приложение", синонимично слову project, "проект". То есть это вот весь код, простите за тавтологию, Rails-приложения, который вы храните в отдельном репозитории. В Django проторенными дорожками не ходят, поэтому там application это отдельный пакет внутри вашего проекта.
На пакетах (packages) стоит остановиться подробней. В Rails за вас работает система автоимпорта и весь код (при настройках по умолчанию) загружается в память при старте (на тонкостях останавливаться не будем).
Если в папке
В Django всё не так просто.
Во-первых, вам всегда надо вручную импортировать классы из пакетов:
В строке импорта выше
Для того, чтобы всё заработало, вам надо добавить строку "car_service" в массив подключенных приложений (
Поэтому, переходя с Rails на Django, надо понять, что весь код программисты конкретного приложения разбили, произвольно, на набор вот этих пакетов-приложений, и модель Car вы найдёте в файле
#programming #django #python
Однако при более подробном всматривании и ощупывании всплывает этакий программистский вариант "ложных друзей переводчика". И там, и там есть applications ("приложения"), migrations ("миграции"), views ("представления", здесь перевод не устоявшийся и их обычно "вьюхами" и называют). Но все эти штуки в обоих фреймворках либо существенно отличаются, либо обозначают просто разные вещи.
Вот планирую в небольшом цикле заметок остановиться именно на таких различиях, а сходство больше и не упоминать.
В Django опорный паттерн называется MVT, model-view-template. В Rails он называется MVC, model-view-controller. Разница только терминологическая: то что в Rails называют views (перемешанные фрагменты HTML-кода и управляющих операторов), в Django называют templates. То, что в Rails называют controllers (класс, обрабатывающий запрос) в Django называют views (может быть классом, а может быть отдельной функцией). Здесь достаточно один раз привыкнуть, задать риторический вопрос "зачем надо было всё перемешивать?", и дальше спокойно работать.
В Rails слово application, "приложение", синонимично слову project, "проект". То есть это вот весь код, простите за тавтологию, Rails-приложения, который вы храните в отдельном репозитории. В Django проторенными дорожками не ходят, поэтому там application это отдельный пакет внутри вашего проекта.
На пакетах (packages) стоит остановиться подробней. В Rails за вас работает система автоимпорта и весь код (при настройках по умолчанию) загружается в память при старте (на тонкостях останавливаться не будем).
Если в папке
app/models/car.rb
лежит класс Car
, то вам достаточно в коде написать Car
, и Rails его найдут.В Django всё не так просто.
Во-первых, вам всегда надо вручную импортировать классы из пакетов:
from car_service.models import Car
. В этом есть плюс: IDE всегда знает, откуда что взялось. Минус: существенное увеличение boilerplate-а и когнитивной нагрузки на его обслуживание.В строке импорта выше
car_service
это, в терминах Python, имя пакета (имя выбрано произвольно: допустим, мы делаем бэкофис для автомастерской). А в терминах DJango, это имя "приложения" (application). models.py
– имя файла, где лежит исходный код класса Car
. Да, в Django в один файл принято запихивать десяток классов. Это одно из многих проявлений знаменитого питоновского акцента на красоту и элегантность кода.Для того, чтобы всё заработало, вам надо добавить строку "car_service" в массив подключенных приложений (
INSTALLED_APPS
) в settings.py
(файл настроек проекта). (Кстати, термин application здесь в итоге близок тому, как он понимается в экосистеме Elixir/Phoenix.) В терминах Rails этому car_service
нет прямого аналога, иногда что-то подобное можно назвать "ресурсом" (resource, в терминах REST), иногда bounded context (опять же в Phoenix более прямые аналоги).Поэтому, переходя с Rails на Django, надо понять, что весь код программисты конкретного приложения разбили, произвольно, на набор вот этих пакетов-приложений, и модель Car вы найдёте в файле
car_service/models.py
, а модель User в папке accounts/models.py
.#programming #django #python
Питоновские пакеты, из-за обязательного явного импорта, могут экспортировать не только классы, но и переменные или константы:
Как было сказано выше, в Django в роли "вьюх" (т.е., в терминах Rails, "контроллеров") могут выступать отдельные функции. А могут и классы. Первое называется function based views, а второе class based views.
Привыкшему к REST веб-разработчику сподручнее сразу использовать class based views, чтобы не получать очередного когнитивного диссонанса от использования конструкций вроде
#programming #django #python
# some_file.pyПолучается своеобразная двойная иерархия: классы наследуют друг друга, а пакеты друг из друга импортируют всякую всячину. Поэтому в Питоне, где можно, частенько классы и не создают, просто группируют функции внутри файла (и файлы внутри пакета), и импортируют их в других файлах (и других пакетах). В Ruby для создания коллекции функций обязательно использовать, по меньшей мере, модули (modules); но вообще в качестве стандартной единицы распространения кода выступает класс, при этом имя файла (по соглашению/кодстайлу) однозначно соответствует имени класса (и в одном файле всегда только один класс).
NUMBER = 1
# another_file.py
from .some_file import NUMBER
print(NUMBER) #=> 1
Как было сказано выше, в Django в роли "вьюх" (т.е., в терминах Rails, "контроллеров") могут выступать отдельные функции. А могут и классы. Первое называется function based views, а второе class based views.
Привыкшему к REST веб-разработчику сподручнее сразу использовать class based views, чтобы не получать очередного когнитивного диссонанса от использования конструкций вроде
if request.method == 'POST'
в мейнстримном фреймворке, созданном на самом элегантном языке программирования.#programming #django #python
Следующее существенное отличие Django от Rails это система миграций
В Rails миграции это просто тонкая обёртка над SQL-кодом: добавь такой-то столбец, удали такой и т.д. Все миграции хранятся в одной папке в хронологическом порядке. Движок определяет, какие миграции прошли, на основе того, есть ли отметка о данной миграции в специальной служебной таблице в базе данных.
В Django тоже есть аналогичная таблица, но этим дело не заканчивается. Во-первых, миграции разделены по "приложениями" (см. выше). В каждом приложении хранятся миграции (по конвенции), касающиеся моделей этого приложения. Вместо подразумеваемой цепочки зависимостей из Rails (где мы, фактически, считаем, что каждая миграция зависит от всех по времени более ранних), в Django в начале каждой миграции явно указывается, от каких предыдущих она зависит (они могут быть из других "приложений"). Получается сложный граф зависимостей.
Представим, что во время рефакторинга мы удалили некое "приложение" или два "приложения" объединили в одно. Что происходит с миграциями? Происходит, как можно догадаться, fuck up beyond all repair. Вам придётся либо оставить миграции в покое (удалив из устаревшего "приложения" все другие файлы), либо переписать все миграции, фактически, с нуля. Элегантному фреймворку – элегантные решения.
Далее важно понять, что в Django миграции это не простые прямолинейные команды для движка. Это декларация о том, что должно быть в базе данных. Когда мы пишем в миграции А "добавить столбец X, Y", а в миграции B (следующей по времени позже A) "добавить столбец Z, удалить столбец X", движок (во время исполнения миграций, когда он считывает все файлы) понимает: "ага, у нас в базе сейчас столбцы Y, Z" (важно отметить, что к базе данных при этом он подключается только для получения списка уже сделанных миграций – если вы там сами что-то наворотили отдельно, то всё сломается).
Django формирует, на основе виртуального суммирования всех миграций, некое своё (точное) представление о том, какая сейчас структура в БД (исходя из того, что она создавалась исключительно миграциями). Это называется State, "состояние".
Затем Django доходит до миграций, которые ещё не были выполнены, и выполняет соответствующие SQL-инструкции (database operations). Здесь операция вроде "добавить столбец M" выступает уже в двух ролях:
– во-первых, как database operation (аналогично Rails) – инструкции буквально выполнить
Как можно было предполагать, этот изящный подход к проблеме от, как складывается впечатление, какого-то победителя региональных олимпиад по computer science, в реальных приложениях работает отлично 80% времени. Оставшиеся 20% времени вам потребуется, вырывая волосы на голове, вгрызаться в (довольно сложный, но всё же за пару дней можно разобраться) DSL миграций и писать миграции типа SeparateDatabaseAndState (это когда вы буквально говорите Django, мол, я сам в базе произведу нужные операции, не надо "читать мысли", а потом отдельно ещё ему объясняете для этого "внутреннего образа схемы БД", что же вы сделали).
Тема миграций напрямую связана с темой моделей. Модели в Django требуют явного указания полей (похоже на gem DataMapper), в то время как в Rails поля подгружаются в рантайме из базы данных. Явное указание полей модели позволяет делать "автомиграции" – написать команду, которая (в соответствии с теми изменениями, что вы внесли в моделях, сравнивая их со State, который был вычислен из предыдущих миграций) сгенерирует миграцию, в которой удаляются (добавляются, изменяются) соответствующие поля. Это издевательски небольшая, но иррационально приятная компенсация за все прочие мучения.
#programming #django
В Rails миграции это просто тонкая обёртка над SQL-кодом: добавь такой-то столбец, удали такой и т.д. Все миграции хранятся в одной папке в хронологическом порядке. Движок определяет, какие миграции прошли, на основе того, есть ли отметка о данной миграции в специальной служебной таблице в базе данных.
В Django тоже есть аналогичная таблица, но этим дело не заканчивается. Во-первых, миграции разделены по "приложениями" (см. выше). В каждом приложении хранятся миграции (по конвенции), касающиеся моделей этого приложения. Вместо подразумеваемой цепочки зависимостей из Rails (где мы, фактически, считаем, что каждая миграция зависит от всех по времени более ранних), в Django в начале каждой миграции явно указывается, от каких предыдущих она зависит (они могут быть из других "приложений"). Получается сложный граф зависимостей.
Представим, что во время рефакторинга мы удалили некое "приложение" или два "приложения" объединили в одно. Что происходит с миграциями? Происходит, как можно догадаться, fuck up beyond all repair. Вам придётся либо оставить миграции в покое (удалив из устаревшего "приложения" все другие файлы), либо переписать все миграции, фактически, с нуля. Элегантному фреймворку – элегантные решения.
Далее важно понять, что в Django миграции это не простые прямолинейные команды для движка. Это декларация о том, что должно быть в базе данных. Когда мы пишем в миграции А "добавить столбец X, Y", а в миграции B (следующей по времени позже A) "добавить столбец Z, удалить столбец X", движок (во время исполнения миграций, когда он считывает все файлы) понимает: "ага, у нас в базе сейчас столбцы Y, Z" (важно отметить, что к базе данных при этом он подключается только для получения списка уже сделанных миграций – если вы там сами что-то наворотили отдельно, то всё сломается).
Django формирует, на основе виртуального суммирования всех миграций, некое своё (точное) представление о том, какая сейчас структура в БД (исходя из того, что она создавалась исключительно миграциями). Это называется State, "состояние".
Затем Django доходит до миграций, которые ещё не были выполнены, и выполняет соответствующие SQL-инструкции (database operations). Здесь операция вроде "добавить столбец M" выступает уже в двух ролях:
– во-первых, как database operation (аналогично Rails) – инструкции буквально выполнить
ALTER TABLE...
– во-вторых, как state operation – инструкции обновить "внутренний образ" того, какая у нас текущая структура базы данныхКак можно было предполагать, этот изящный подход к проблеме от, как складывается впечатление, какого-то победителя региональных олимпиад по computer science, в реальных приложениях работает отлично 80% времени. Оставшиеся 20% времени вам потребуется, вырывая волосы на голове, вгрызаться в (довольно сложный, но всё же за пару дней можно разобраться) DSL миграций и писать миграции типа SeparateDatabaseAndState (это когда вы буквально говорите Django, мол, я сам в базе произведу нужные операции, не надо "читать мысли", а потом отдельно ещё ему объясняете для этого "внутреннего образа схемы БД", что же вы сделали).
Тема миграций напрямую связана с темой моделей. Модели в Django требуют явного указания полей (похоже на gem DataMapper), в то время как в Rails поля подгружаются в рантайме из базы данных. Явное указание полей модели позволяет делать "автомиграции" – написать команду, которая (в соответствии с теми изменениями, что вы внесли в моделях, сравнивая их со State, который был вычислен из предыдущих миграций) сгенерирует миграцию, в которой удаляются (добавляются, изменяются) соответствующие поля. Это издевательски небольшая, но иррационально приятная компенсация за все прочие мучения.
#programming #django
Rails-разработчик, однажды наступив на грабли, знает, что в миграциях нельзя использовать код моделей. Модель может быть изменена или удалена, а миграция (в идеале) должна работать "с нуля" на свежей версии кода.
Django, будучи способным вычислить State, знает, какие поля у каких моделей в какой момент времени (на момент исполнения какой миграции) существовали. Поэтому внутри миграции вы, через специальный DSL, можете получить "призрак" класса своей модели на момент прохождения данной миграции: в ней будут все стандартные методы и ассоциации (но, конечно, все кастомные методы будут недоступны).
#programming #django
Django, будучи способным вычислить State, знает, какие поля у каких моделей в какой момент времени (на момент исполнения какой миграции) существовали. Поэтому внутри миграции вы, через специальный DSL, можете получить "призрак" класса своей модели на момент прохождения данной миграции: в ней будут все стандартные методы и ассоциации (но, конечно, все кастомные методы будут недоступны).
#programming #django
Продолжаем цикл "Django глазами Rails-разработчика" (1/3)
Скопилось некоторое количество заметок для себя, которые, как мне кажется, могут быть полезны любому Rails-разработчику, начавшему использовать Django (или наоборот, хоть и в меньшей мере). Не смотря на то, что заметки по понятной причине (поводом для их создания служило, в первую очередь, раздражение от необходимости в очередной раз бороться с фреймворком на ровном месте) сфокусированы на каких-то "острых углах", в целом впечатление довольно ровное и, местами, даже положительное (позитив будет в конце).
Поехали: на что надо обращать внимание Rails-pазработчику в отношении Django, чтобы избежать когнитивного диссонанса и сэкономить время.
1. В Django нет единого кодстайла. Переходя с Rails, где формат названия классов (и файлов, в которых лежат классы), методов, модулей, путей и т.д. строго формализован, и ожидая от фреймворка разрекламированно элегантного языка подобного, рискуешь получить когнитивный диссонанс. В разных популярных библиотеках название метода может быть
2. Примеры кода из документации могут просто не работать в окружении той же версии, для которой написана документация. Часто "есть нюанс", который описан где-то на соседних страницах.
3. Всё может падать без поднятия исключений. Например, сломаться какая-то функция в шаблоне или логгирование – узнать об этом можно только по отсутствию эффекта, сообщения об ошибке может не быть.
4. Пожалуй, худший язык шаблонов из всех существующих. В целом эзотерический синтаксис вызова "хелпер"-функций (которые, создавая дополнительную сложность, разделяют на "фильтры" и "теги") усложняется отсутствием элементарной функциональности: невозможно взять элемент из хеша (по ключу, хранящемуся в переменной), невозможно вызвать метод прокинутого в шаблон объекта (хотя можно взять значение любого атрибута), нельзя сделать присвоение переменной (например, для конкатенации двух строк), и т.д. Хотелось бы оправдать такую ограниченость шаблонов соображениями безопасности (например, liquid-шаблоны известного e-commerce сервиса Shopify, используемые для кастомизации вида пользовательских витрин/магазинов, используют похожий синтаксис, не позволяя при этом писателю шаблона "вылезти из песочницы"), но это будет большой натяжкой: всё равно можно залезть куда угодно через переданные объекты, пользовательский код шаблонов исполнять нельзя.
5. Для нормальной отладки надо использовать сторонние решения (например, debug toolbar). Например, вы иначе не сможете посмотреть код SQL-запросов – в логах их отображение прямолинейным путём не получиться добиться. Впрочем, типовые сторонние решения удобные и достойные, сглаживающие этот недостаток фреймворка.
6. Кстати, про SQL-запросы: в Django нет SQL-кеша. Достали из базы модель по одному и тому же primary key десять раз – получите десять запросов в базу.
7. Открытые (и актуальные) баги десятилетней давности во фреймворке и брошенные мейнстримные пакеты – это норма.
8. Обновление на одну минорную версию какого-то там пакета, который являлся зависимостью какого-то там ещё пакета, который является зависимостью пакета, который вы используете, которое всё сломало – запросто. См. предыдущие посты по тегу про отсутствие встроенного менеджера пакетов (с той функциональностью, которая есть во всех других современных языках – например, lock-файлом) и необходимость использовать сторонние решения.
9. Кстати, про пакеты. В мире Rails для каждой распространённой задачи (как правило) есть гем, являющийся явным "гегемоном". В Django (как правило) существует два и более способа что-то сделать (поддерживаемых pypi пакета), причём оба плохи.
#programming #django #rails
Скопилось некоторое количество заметок для себя, которые, как мне кажется, могут быть полезны любому Rails-разработчику, начавшему использовать Django (или наоборот, хоть и в меньшей мере). Не смотря на то, что заметки по понятной причине (поводом для их создания служило, в первую очередь, раздражение от необходимости в очередной раз бороться с фреймворком на ровном месте) сфокусированы на каких-то "острых углах", в целом впечатление довольно ровное и, местами, даже положительное (позитив будет в конце).
Поехали: на что надо обращать внимание Rails-pазработчику в отношении Django, чтобы избежать когнитивного диссонанса и сэкономить время.
1. В Django нет единого кодстайла. Переходя с Rails, где формат названия классов (и файлов, в которых лежат классы), методов, модулей, путей и т.д. строго формализован, и ожидая от фреймворка разрекламированно элегантного языка подобного, рискуешь получить когнитивный диссонанс. В разных популярных библиотеках название метода может быть
setup
, set_up
, setUp
: это норма.2. Примеры кода из документации могут просто не работать в окружении той же версии, для которой написана документация. Часто "есть нюанс", который описан где-то на соседних страницах.
3. Всё может падать без поднятия исключений. Например, сломаться какая-то функция в шаблоне или логгирование – узнать об этом можно только по отсутствию эффекта, сообщения об ошибке может не быть.
4. Пожалуй, худший язык шаблонов из всех существующих. В целом эзотерический синтаксис вызова "хелпер"-функций (которые, создавая дополнительную сложность, разделяют на "фильтры" и "теги") усложняется отсутствием элементарной функциональности: невозможно взять элемент из хеша (по ключу, хранящемуся в переменной), невозможно вызвать метод прокинутого в шаблон объекта (хотя можно взять значение любого атрибута), нельзя сделать присвоение переменной (например, для конкатенации двух строк), и т.д. Хотелось бы оправдать такую ограниченость шаблонов соображениями безопасности (например, liquid-шаблоны известного e-commerce сервиса Shopify, используемые для кастомизации вида пользовательских витрин/магазинов, используют похожий синтаксис, не позволяя при этом писателю шаблона "вылезти из песочницы"), но это будет большой натяжкой: всё равно можно залезть куда угодно через переданные объекты, пользовательский код шаблонов исполнять нельзя.
5. Для нормальной отладки надо использовать сторонние решения (например, debug toolbar). Например, вы иначе не сможете посмотреть код SQL-запросов – в логах их отображение прямолинейным путём не получиться добиться. Впрочем, типовые сторонние решения удобные и достойные, сглаживающие этот недостаток фреймворка.
6. Кстати, про SQL-запросы: в Django нет SQL-кеша. Достали из базы модель по одному и тому же primary key десять раз – получите десять запросов в базу.
7. Открытые (и актуальные) баги десятилетней давности во фреймворке и брошенные мейнстримные пакеты – это норма.
8. Обновление на одну минорную версию какого-то там пакета, который являлся зависимостью какого-то там ещё пакета, который является зависимостью пакета, который вы используете, которое всё сломало – запросто. См. предыдущие посты по тегу про отсутствие встроенного менеджера пакетов (с той функциональностью, которая есть во всех других современных языках – например, lock-файлом) и необходимость использовать сторонние решения.
9. Кстати, про пакеты. В мире Rails для каждой распространённой задачи (как правило) есть гем, являющийся явным "гегемоном". В Django (как правило) существует два и более способа что-то сделать (поддерживаемых pypi пакета), причём оба плохи.
#programming #django #rails
Продолжаем цикл "Django глазами Rails-разработчика" (2/3)
В продолжение предыдущего поста:
10. И в целом, в Python/Django, в отличие от Ruby/Rails, регулярно встречаются ситуации, когда есть два (три, четыре...) способа сделать элементарную вещь, причём все плохие. Например, в Python нет нормальной интерполяции строк (и в Django аналогично с интерполяцией фрагментов HTML). Зато есть три (или четыре?) плохих способа. В Python нет нормального способа проверить существование файла – опять, вместо этого предлагают три-четыре костыля. Нет нормального фреймворка для тестирования (справедливости ради, здесь всё же есть мейнстримный pytest, т.е. только одно плохое решение, а не несколько, что хотя бы избавляет от мук выбора). И т.д.
11. В Django работа с почтой реализована на уровне Rails 2.x (то есть примерно 2007 года).
12. В Django ужасно некрасивый по форме и кривой по функциональности ORM. В Rails в целом понимают, что ORM нужен для пяти операций, которые покрывают 90% функциональности. В Django прямо заявляют, что ORM должен покрывать 100% кейсов, а про SQL забудьте, это другой уровень абстракции. Поэтому то, что в Rails решается вставкой SQL-кода из пяти ключевых слов в одну функцию внутри scope-а (метода класса; в Django аналогом будет метод "менеджера"), в Django превращается в попытку описать ограниченными и криво работающими примитивами Django-классов то, чего вы хотите получить, но сильно обходным путём (по сути такое описание AST-дерева SQL инструкции через сборку Django-классов, определяющих узлы этого дерева). Подобный идиотизм был и в Phoenix-е (фреймворке на Elixir-е), но там всё же мучения были, по воспоминаниям, гораздо меньше из-за того, что функциональный язык для таких штук прямо приспособлен.
13. Кстати, про ORM. В Django крайне затруднительно создать работающее виртуальное (computed, не существующее в базе данных) поле. В Rails с этим никаких проблем: определяем атрибут в модели, просто как в обычном Ruby-классе, и в формах всё работает. Впрочем, см. п.5 в следующем посте.
#programming #django #rails
В продолжение предыдущего поста:
10. И в целом, в Python/Django, в отличие от Ruby/Rails, регулярно встречаются ситуации, когда есть два (три, четыре...) способа сделать элементарную вещь, причём все плохие. Например, в Python нет нормальной интерполяции строк (и в Django аналогично с интерполяцией фрагментов HTML). Зато есть три (или четыре?) плохих способа. В Python нет нормального способа проверить существование файла – опять, вместо этого предлагают три-четыре костыля. Нет нормального фреймворка для тестирования (справедливости ради, здесь всё же есть мейнстримный pytest, т.е. только одно плохое решение, а не несколько, что хотя бы избавляет от мук выбора). И т.д.
11. В Django работа с почтой реализована на уровне Rails 2.x (то есть примерно 2007 года).
12. В Django ужасно некрасивый по форме и кривой по функциональности ORM. В Rails в целом понимают, что ORM нужен для пяти операций, которые покрывают 90% функциональности. В Django прямо заявляют, что ORM должен покрывать 100% кейсов, а про SQL забудьте, это другой уровень абстракции. Поэтому то, что в Rails решается вставкой SQL-кода из пяти ключевых слов в одну функцию внутри scope-а (метода класса; в Django аналогом будет метод "менеджера"), в Django превращается в попытку описать ограниченными и криво работающими примитивами Django-классов то, чего вы хотите получить, но сильно обходным путём (по сути такое описание AST-дерева SQL инструкции через сборку Django-классов, определяющих узлы этого дерева). Подобный идиотизм был и в Phoenix-е (фреймворке на Elixir-е), но там всё же мучения были, по воспоминаниям, гораздо меньше из-за того, что функциональный язык для таких штук прямо приспособлен.
13. Кстати, про ORM. В Django крайне затруднительно создать работающее виртуальное (computed, не существующее в базе данных) поле. В Rails с этим никаких проблем: определяем атрибут в модели, просто как в обычном Ruby-классе, и в формах всё работает. Впрочем, см. п.5 в следующем посте.
#programming #django #rails
Продолжаем цикл "Django глазами Rails-разработчика" (3/3)
В завершении цикла обещанный позитив:
1. В шаблонах Django используется интересный и, в целом, функциональный механизм наследования. Он более последовательный и логичный чем система layouts и partials из Rails. В Django любую вьюху можно отнаследовать от любой другой (например, зашитой в сторонний пакет или встроенную админку), а затем точно также отнаследовать ещё одну и т.д. Родительская вьюха через инструкцию block (аналог content_for из Rails) обозначает места, куда дочерняя может (через ту же инструкцию) вставить контент (заменив или дополнив тот, что туда прописала одна из родительских вьюх). Вещи типа двух (трёх, четырёх...) лэйаутов для одной вьюхи реализую логично и прямолинейно, в отличие от Rails, где это делается с помощью хитрых манёвров и велосипедостроения.
2. В Django встроенная админка с довольно неплохой функциональностью. В целом она вызывает смешаные чувства восхищения и раздражения. Первое – когда делаешь нечто стандартное, а второе – когда пытаешься дописать свою функциональность (пусть создатели фреймворка и не сделали этот процесс очень удобным или элегантным, но явно предусмотрели все необходимые "точки расширения"). Увы, я не пользовался active-admin или аналогичными гемами, поэтому не могу сравнить с прямыми аналогами из мира Rails: наверное, там примерно такое же впечатление осталось бы.
3. До какого-то времени в Python не было оператора case. "Используйте if или хеши (dict-ы)". В последнюю версию добавили pattern matching, который, на первый и беглый взгляд, производит впечатление менее небрежной работы, чем аналог из последних версий Ruby (на практике в обоих языках использовал эту фичу, пока что, весьма мало для вердикта).
4. В Django встроено управление пользователями. Создавая новый проект, не надо с нуля создавать модель пользователя, функциональность управления паролями, расписывать логику токенов подтверждения почты и вот это всё. На мой взгляд, это удобней использования рубишного гема devise (который, зачастую, добавляет уже слишком много всего).
5. В Django есть встроенная абстракция "форм" (form objects). Промежуточный слой между моделями (прибиты гвоздями к базе данных) и интерфейсом пользователя (который вовсе не обязан вводить данные в том формате, который используется у вас в БД) это очевидная необходимость, и в Rails не является частью фреймворка только из-за специфических анахроничных взглядов DHH на архитектуру типового веб-приложения. (Частично компенсируется наличием сторонних gem-ов.)
#programming #django #rails
В завершении цикла обещанный позитив:
1. В шаблонах Django используется интересный и, в целом, функциональный механизм наследования. Он более последовательный и логичный чем система layouts и partials из Rails. В Django любую вьюху можно отнаследовать от любой другой (например, зашитой в сторонний пакет или встроенную админку), а затем точно также отнаследовать ещё одну и т.д. Родительская вьюха через инструкцию block (аналог content_for из Rails) обозначает места, куда дочерняя может (через ту же инструкцию) вставить контент (заменив или дополнив тот, что туда прописала одна из родительских вьюх). Вещи типа двух (трёх, четырёх...) лэйаутов для одной вьюхи реализую логично и прямолинейно, в отличие от Rails, где это делается с помощью хитрых манёвров и велосипедостроения.
2. В Django встроенная админка с довольно неплохой функциональностью. В целом она вызывает смешаные чувства восхищения и раздражения. Первое – когда делаешь нечто стандартное, а второе – когда пытаешься дописать свою функциональность (пусть создатели фреймворка и не сделали этот процесс очень удобным или элегантным, но явно предусмотрели все необходимые "точки расширения"). Увы, я не пользовался active-admin или аналогичными гемами, поэтому не могу сравнить с прямыми аналогами из мира Rails: наверное, там примерно такое же впечатление осталось бы.
3. До какого-то времени в Python не было оператора case. "Используйте if или хеши (dict-ы)". В последнюю версию добавили pattern matching, который, на первый и беглый взгляд, производит впечатление менее небрежной работы, чем аналог из последних версий Ruby (на практике в обоих языках использовал эту фичу, пока что, весьма мало для вердикта).
4. В Django встроено управление пользователями. Создавая новый проект, не надо с нуля создавать модель пользователя, функциональность управления паролями, расписывать логику токенов подтверждения почты и вот это всё. На мой взгляд, это удобней использования рубишного гема devise (который, зачастую, добавляет уже слишком много всего).
5. В Django есть встроенная абстракция "форм" (form objects). Промежуточный слой между моделями (прибиты гвоздями к базе данных) и интерфейсом пользователя (который вовсе не обязан вводить данные в том формате, который используется у вас в БД) это очевидная необходимость, и в Rails не является частью фреймворка только из-за специфических анахроничных взглядов DHH на архитектуру типового веб-приложения. (Частично компенсируется наличием сторонних gem-ов.)
#programming #django #rails