Спасибо за статью, действительно полезно. Но вот меня всегда удивлял призыв делать толстые модели. Ведь по логике в Django встроен классический паттерн Документ (модель) — Вид (шаблон) — Контроллер (Вид). И логично делать модель и шаблон тонкими, а всю логику помещать в Вид.
объясните, пожалуйста, почему логично?
Чтобы не смешивать данные и логику. Тогда каждый класс отвечает за одно дело — шаблон за отображение, Модель — за хранение данных, а Вид — за бизнес-логику. А так становится непонятным, зачем нужен Вид.
а что вы вообще считаете бизнес-логикой?
на мой взгляд бизнес-логика это как раз такая логика, которая работает с данными и соответственно должна быть рядом с ними
а вид должны отвечать за обработку входных параметров, возможно обработку ошибок, подготовку результатов к выводу и тд
Я под бизнес-логикой понимаю логику, которая связывает вместе работу нескольких моделей. На мой взгляд одна модель не должна ничего знать о существовании других моделей.

Размещая БЛ во view вы сами себя лишаете возможности повторно использовать свой же код. Сильно толстые модели тоже плохо, но никто не запрещает делать "бизнес-прослойку" между view и models

Так Вы приходите к тому, что БД выступает только как умное хранилище, а всю логику переносите во вьюхи. Противоположный случай — максимальное количество логики в модели, если отойти от джанги — то на вьюхах, процедурах и триггерах СУБД, так приходим к двухзвенной архитектуре. В случае трехзвенной архитектуры, в моделях описываем логику хранения и отображения данных, во View — взаимодействие с клиентом

Логику внутрь View? Представьте, сколько времени займет редизайн проекта.
Наоборот, толстые модели заставляют смешивать в одном классе логику и данные.
Если модель получается слишком толстой — напишите рядом с ней контроллер или фабрику или любую другую подходящую структуру. Паттерны никто не отменял и наоборот они часто помогают даже в django.

Толстых моделей жалательно избегать по-возможности. Всю логику лучше держать в logic или utils. В моделях оставлять логику, относящуюся конкретно к данным, напр, какие-то property. Иначе модель может разрастись до 400-500 строк (это не редкость в каждом втором крупном проекте).

Вот соглашусь. Модель — по-возможности, только для доступа к базе.
Однако очень часто я пропускаю тот момент когда она сильно разрастается, а переписывать уже некогда…

Разбивайте на submodules:
https://stackoverflow.com/questions/6336664/split-models-py-into-several-files


И views также можно разбить. Хотя лучше конечно новый app и туда часть перенести.

Да, именно так. Но я имел в виду более сложный случай. Когда босле пары месяцев активного добавления новых «фич» одна модель или вьюшка перерастает размер в 300-500 строк.

Разбивайте на миксины (если это классы). У меня например по генерации и отправке email нотификаций миксины и классы в emails.py. Затем миксин или класс импортируется в models.py / views.py. Ну и tasks.py для celery.

В джанге view = контроллер.

Дизайн в шаблонах (templates)
Может, в Контроллер, а не в Вид?
В Django исторически принято так, что:
— то что в стандартной MVC модели называют «Controller» в Django называют «views»
— а то что в стандартной MVC модели «View» в Django называют «templates».
не совсем так. В джанге контроллеры и вьюхи объединили во views(можно сказать, что от самих контроллеров отказались). А шаблоны — они шаблоны и есть, текстовые файлы в специальной разметке для замены и подстановки в них данных.
В классической версии модель была ровно одна на всё приложение, и поэтому проблем было меньше.

Как именно предлагаете тестировать логику в видах? Юнит-тесты станут невозможны и нужно будет писать уйму интеграционных, да?
НЛО прилетело и оставило эту надпись здесь.

Мне одному не нравятся Class-based Views? Неохота доказывать/объяснять почему (слишком субъективно), просто интересно, есть ли ещё такие

Я ниже немного накинул на вентилятор.
не одному, и к оригинальной статье есть пара развернутых комментариев на счет этого от core django разработчика

В документации так и написано:


Class-based views provide an alternative way to implement views as Python objects instead of functions.

Этот способ не лучше и не хуже, он просто другой. И да, вы не один))

Конечно не Вам одному.
Но вообще посмотрите на дату публикации — вполне себе веселое пятничное чтиво.
Меня вот начало веселить прямо с «ошибки» №1.
CBV — это худшее, что есть в Django. Совершенно дурацкое усложнение, которое на ровном месте ставит палки в колёса композиции логики, а исследовать поведение методов иногда совершенно нетривиально из-за необходимости ходить туда-сюда по всему дереву наследования и удерживать в голове весь контекст переопределения. В принципе, это общая проблема множественного наследования, но в Django идея возведена в абсолют. 100500 вьюх, базовых вьюх, миксинов… при том, что в любом случае приходится переопределять подавляющее большинство их методов. При разрастании кодовой базы это всё какой-то ад для поддержки и модификации.
Как только команда разработчиков стала насчитывать людей больше 1, так сразу CBV и проникся.
Мне тоже так казалось сначала. Но после некоторой практики я понял, что CBV − отличная вещь, просто у них есть некоторый порог вхождения. Нарисуйте на бумаге диаграммы вызовов в каком-нибудь DetailView, и через неделю этот класс станет для вас родным. Будете удивляться, как это вы раньше могли писать гору шаблонного кода вроде “if request.method == 'POST'”.

Если вам пришлось переопределять большинство методов − вы, скорее всего, наследуетесь не от того класса.
Я рисовал дерево наследования всех классов и миксеров Django как только CBV вообще появились. На более-менее простых проектах всё можно контролировать. На большом проекте и с большой командой контроль стремится к нулю. Я счастлив, что больше не приходится использовать ни CBV, ни Django в принципе.
не поделитесь, что сейчас используете?
На текущем проекте, в зависимости от приложения, Pyramid или aiohttp. На предыдущем была Tornado. В Pyramid и Tornado вьюхи в общем-то тоже на классах, но на самом деле это только точка входа для дальнейшей композиции функций. В aiohttp всё честно сразу :)
Понимание портится не от CBV, а от структуры этих CBV классов, если у вас десятки миксинов, и везде используется множественное наследование, от парочки классов + миксины, будьте готовы выхватывать

Работал над большими и маленькими проектами. Ни разу с проблемами не сталкивался. Ну, кроме того, что некоторые разработчики излишне ретиво создают миксины, и потом наследуются от 20 миксинов, которые делают кучу лишней работы. Но это просто проблема с конкретными разработчиками, а не CBV в принципе.


Так они позволяют очень легко и наглядно переиспользовать код. На их основе, например, сделал недавно систему, которая генерирует HTML, PDF и Excel отчеты. Повторяющегося кода нет вообще благодаря CBV. Все детали конкретного формата обрабатываются миксинами.

Согласен, CBV дают упрощение только в простых случаях. В сложных случаях получается сложнее, чем использовать обычные view. Особенно проявляется, когда используешь DRF. Все, что выбивается за рамки простого CRUD вокруг моделей, реализовывать неудобно.


Вообще, едиственная задача ООП — уменьшение сложности. Если в классе минимум 5 миксинов (обычная практика), переписать на обычные view — хорошая задача для рефакторинга.

А что тогда вы скажите про forms в Django?

Чтобы не было слишком много миксинов, нужно базовые CBV делать достаточно мощными. Может быть в них будет несколько редко используемых методов, но этот компромисс лучше чем попытка загнать абсолютно все в миксины.


Использую и CBV и миксины для них, за счет того что базовые CBV большие и многофункциональные, миксинов немного, чаще используется обычное наследование с переопределением нескольких методов:


https://github.com/Dmitri-Sintsov/django-jinja-knockout/tree/master/django_jinja_knockout/views

С моей точки зрения основная проблема django — среди 100500 пакетов «на все случаи жизни», которые надо «использовать вместо велосипедов» больше 50% — не работают в текущей версии django ВООБЩЕ, поскольку их авторам джанго уже неинтересен, а core team не особо следит за обратной совместимостью.

А из оставшихся еще 30% очевидным образом не работают, демо проектов не имеют(или пункт 1) и как его использовать непонятно.
Вместо django подставьте %frameworkname% и идите в любой форум любого фреймворка.
У django это доведено до абсурда, в связи с непонятными несовместимостями ядра и РАЗНЫМИ requirments.txt

Очень часто проще реализовать самому функционал на 5 строчек, чем лепить непонятные зависимости в проект. Тут дело не в велосипедостроении, а в целесобразности. По настоящему хороших пакетов — единицы.

Неправда. Я работаю много лет над двумя очень большими и посещаемыми проектами, и двумя поменьше. В каждом размер requirements.txt от 40 до 100+ строк.


Существует масса отличных поддерживаемых пакетов. Бывает, что разработчики не успевают за версиями Django (причем не всегда при этом совместимость ломается, например, последний переход 1.10-1.11 практически безболезненный), тогда достаточно на GitHub поискать обновленный форк, чаще всего он находится. Если не находится, как правило, очень быстро можно допилить свой. И создать pull request.


А вот те, кто пишут велосипеды. Ребята, за вами очень тяжело поддерживать код. В отличие от готовых пакетов с PyPI/GitHub, у вас нет ни документации, ни примеров, ни комментариев, ни архитектуры.


Да и в большинстве случаев велосипедостроение возникает от незнания и неумения искать на djangopackages, pypi, github и просто google.

Вероятно мы с вами о разных вещах говорим. В стандартных проектах (обычный сайт, магазин) проще взять готовое решение. Если проект в логику CRUD вписывается лишь частично и проект использует из функционала джанги только ORM + DRF то написать 5 строчек предрпочтительнее.

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


А так существует масса полезных батареек для Django. Например:


  • django-allauth
  • django-localflavor
  • django-braces
  • django-crispy-forms
  • django-taggit
  • django-extensions
  • django-select2

Ну и наверное много чего еще не вспомнил. Я видел попытки вместо использования данных (и других) модулей написать свой код. Но ни разу не видел, чтобы получилось лучше.


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


Ну и по-моему опыту так получается почти всегда. В другом проекте написан свой модуль для работы с ElasticSearch. Абсолютно непонятный, кривой, и с ужасной производительностью. Но на него теперь завязано почти все, и переписать нормально нет возможности. :(


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

Разрешите дополнить, очень часто использую в проектах:
  • django-imagekit
  • django-solo
  • django-leaflet
  • django-modeltranslation
  • django-ckeditor

У всех из вышеперечисленных хорошая (ну или по крайней мере приемлемая) документация.

Я вместо django-solo использую django-constance.

А я до сих пор не могу понять зачем использовать Django как ORM + DRF без inline formsets, admin и прочего что так ценно в Django. Если нужно только серверное API для клиента на react / angular, не лучше ли использовать на сервере node.js?


Я использую AJAX в своих модулях (у меня knockout.js) но подход смешанный — часть кода обычный серверный html, часть AJAX виджеты. Не SPA. Мне кажется что для SPA лучше next.js или что-то подобное.

Испоьзую ORM + DRF + admin, потому, что это удобно, и другие разработчики знают этот стек, документация по DRF отличная. Джанга только часть проекта (не самая важная кстати). Т.к. последний проект разделен на микросервисы, возможно эта часть на джанге будет заменена на что-то другое, возможно вообще не на python.


Ценность джанго админки в том, что далего не всегда целесобразно писать свою, особенно когда пользователи бородатые админы, а не девочки из тех поддержки. В одном проекте на джанго (управление очередями событий) мы вообще отказались от админки, все управление системой шло через консоль (managements commands). Подобное поведение релизовать через веб формы было бы намного сложнее.


Для чего использовать Node.js с его ассинхронностью, если мне нужен именно синхронный фремворк. Если мне будет необходима ассинхронность, я возьму aiohttp.

Да, admin в Django очень хороший, не спорю. Только это классическое приложение не REST и не AJAX. node.js позволяет использовать один язык на серверной стороне и клиентской, в случае AJAX / REST должно быть достаточно.


inline formsets вообще одна из самых ценных фич Django, автоматический маппинг отношений один ко многим с уровня моделей на уровень форм. Вроде бы что-то похожее появилось в последних версиях Angular, массивы форм: https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html


Поддержка множественных форм с отношениями до сих пор большая редкость во фреймворках.

Я не хочу начинать языковой холивар, но мне кажется, что Javascript — плохой язык. Это костыль, который по роковому стечению обстоятельств зажил полноценной жизнью. А вся экосистема Javascript/Node.js — это какой-то сумасшедший калейдоскоп, где каждый день с утра уже надо переписывать проект, потому что поменялись все версии библиотек, поменялась парадигма, поменялась система сборки проекта. Чтобы в этом непрерывно меняющемся зоопарке библиотек и инструментов разбираться… Нет, я уж лучше что-нибудь другое изучу.

Мне тоже Питон больше нравится. Только браузеры его не понимают, поэтому от Javascript все равно никуда не деться в веб-программировании.

Надеюсь, WebAssembly и подобные проекты наконец-то переломят ситуацию. Когда появилась Mozilla, было несколько более-менее успешных попыток внедрить поддержку других языков (в частности, Python и Tcl/Tk). Были даже весьма интересные расширения на этих языках. К сожалению, все это не взлетело… Возможно потому что в то время, не было реальной необходимости в полноценном языке программирования в браузере. Сейчас ситуация другая, и, сильно надеюсь, что Javascript наконец с почестями похоронят. На мой взгляд, это такой PHP для frontend'а.

Судя по тому что в Javascript (как и в PHP) добавляют все больше фич из Python, в том числе генераторы и variadic args, у них планы совсем другие.


Особенно преуспевают разработчики PHP, они вообще похоже изучают PEP и детали CPython. Только при этом основа языка остается кривой: из-за совместимости не поправить.


Ну а в Javascript так и нет нормального наследования, по сравнению с Python особенно бросается в глаза. Нет автоматических нормальных миксинов, нет нормальных метаклассов. Делают extend и миксины вручную, это конечно работает но уступает по изяществу нормальному множественному наследованию в Python.

Люто плюсую за статью
Всегда будут люди, которым надо сделать что-то, не предусмотренное инструкцией. И всегда будут от них жалобы типа «в этом вашем джанго CBV г*вно, потому что мне неудобно сделать %specific_feature%».
Конечно, статья немного субъективна, но думать в любом случае никто не запрещал. Перед началом проекта сядь и подумай — вообще подойдет тебе джанга или будет только камнем?

У меня для многих проектов изначально не было смысла делать веб-интерфейс и я велосипедил с простых скриптов, слегка связанных общими модулями. Для простых одностраничных веб-приложений добавлял Flask. Но потом внезапно понял что структуру проекта я пытаюсь выдерживать в django-стиле, мне не хватает удобных settings, и волшебного django ORM с его моделями.
С недавних пор я по-умолчанию начинаю проект с django-темплейта, выпиливая веб-часть, если не нужна.

Что касается логики во View — достаточно один раз (ок, два — точно достаточно для большинства чтобы осознать) столкнуться с тем, что, внезапно, логика начинает использоваться не только с фронтенда, а еще и с бэкенда (например, из celery-тасков создание или обработка сложных объектов). После этого количество кода логики во view резко уменьшается и появляются либо контроллеры, либо распухают модели, либо появляются отдельные под-приложения, которые могут вызываться откуда угодно.
Надо понимать что View (как бы кто ни говорил о том что в django это модифицированный Controller) предназначена, в первую очередь, для реализации схемы request-response и использовать ее с другой целью — смысла мало.

Люди, которые не любят CBV и используют функции для вьюшек — я вам откровенно и честно завидую! У вас, наверное, достаточно времени на качественный рефакторинг и требования изначально четкие и не меняются.
В противном случае я не представляю как можно не переиспользовать код в сложном проекте.
Конечно, стандартные классы вьюшек — простейшие и даже для ListView приходится переопределять много методов чтобы сделать то, что нужно. Но это в любом фреймворке так. Для простого прототипа достаточно django admin, но упаси Нортон строить дальше логику на нем!

Вот, кстати, я бы добавил 11ю ошибку — «использование django admin для построения интерфейса приложения». Можно сколько угодно обклеивать холодильник пенопластом, но море он не переплывет, и хорошо если затонет рядом с берегом, а не на полпути (обратно грести дольше).

Конечно, если у вас предполагается NoSQL, высокие нагрузки или очень динамическая структура базы — то вам надо обязательно 7 раз задуматься и не торопиться с выбором. Но и в эту статью тогда не надо идти с комментариями типа «фу».
Люди, которые не любят CBV и используют функции для вьюшек — я вам откровенно и честно завидую! У вас, наверное, достаточно времени на качественный рефакторинг и требования изначально четкие и не меняются.

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

Простите, но вы сами себе противоречите. Для меня CBV — отвратительное решение, которого лучше бы не было совсем, чтобы молодые специалисты не забивали себе голову. CBV в Django — это как ООП в Java (ООП ради ООП). Нет никакого смысла в этих ваших классах, когда для страницы, чуть более сложной чем My Personal Home Page нужно переопределить с пяток методов, зарыться в родительские классы или писать новые миксины.

Да, миксины удобно, но не применимо IRL, к сожалению. Намного красивее и лаконичнее выглядят вью-декораторы. А когда у логика зависит от юзер-инпута — вообще пиши «пропало», CBV превращается в гомункула созданного Виктором Франкенштейном.

Я уже не говорю, про абсолютно блевотную контрукцию

url(r'^register/$', FormView.as_view(form_class=Register, success_url='/thanks/')

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

Я не сомневаюсь что вам, как и любому другому Python-разработчику, приходилось вынужденно залезать в исходники библиотек (django) для того, чтобы отладить что-то. Вы наверняка видели какое количество кода скрыто внутри и для обработки каких ситуаций оно предназначено.
Не все вещи можно удобно использовать с декораторами, иногда ООП-подход очень спасает.

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

ООП в Java — это для перфекционистов, но даже там подход по-своему красив (я не оч люблю Java если что).
Вот вместо CBV я бы поругал сигналы. Хорошо что ими не так много пользуются, а иначе отладка бы превратилась просто в БОЛЬ.
Опять же, я понимаю почему это было сделано и это достаточно элегантная попытка отделить взаимодействие разных частей кода (или библиотек).
Но вот как раз сигналы, на мой взгляд, совершенно не логичная именно для Python идеология.

А что тогда использовать вместо сигналов? Если всё ещё хотеть отделить взаимодействие разных частей кода.

Не надо отделять, если это все внутри вашего кода одного проекта.

Сигналы нужны для взаимодействия со сторонними библиотеками, когда в них встроится нельзя.

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


Не очень понятно, как они могут мешать отладке, это же по сути обычный Observer.

Вам понадобится перезапускать свой проект, используя python manage.py startapp, при каждом изменении шаблона.

startapp используется для создания нового приложения. При чем здесь перезапуск? Возможно вы хотели про runserver написать.

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