А на чем основано ваше мнение?
В Python часто приходят из других языков; я когда начинал писать на python, всюду классы тоже пытался засунуть (и в джанго-сайте вьюхи на классах делал тоже, по своему, CBV не было еще) - все оттого, что просто привык и не умел/боялся код без классов организовывать. Но ничего сложного в том, чтоб по-нормальному организовать все, не наворачивая классы, как оказалось, не было.
Мне не нравятся generic views на CBV, т.к. для того, чтоб понять, что происходит во вьюхе, нужно прочитать код нескольких миксинов и в голове построить, что в каком порядке выполняется (особенно если есть вызовы super()), с учетом MRO. С вьюхой на функциях “поток выполнения” читается сразу, а с классом он то “заныривает” куда-то во внутренности джанги, то “выныривает” оттуда.
Возьмем какой-нибудь ArchiveIndexView - если там что-то захочется поправить, нужно прочитать код MultipleObjectTemplateResponseMixin, BaseArchiveIndexView, BaseDateListView, DateMixin, MultipleObjectMixin (названия-то какие); понять, метод какого из классов будет в итоге вызываться с учетом MRO, в какой последовательности будет разворачиваться цепочка super-вызовов, найти метод, который лучше всего перекрыть, и переопределить его. Другими словами, думать об абстракциях и деталях реализации фреймворка вместо того, чтоб взять да написать необходимую логику.
Со временем, конечно, детали основных классов запомнятся, и будет вполне очевидно, какой метод нужно перекрыть - до тех пор, пока не начнешь поддерживать код другого разработчика, который надстроил свою иерархию классов. Или ладно, запомнили, какие методы и что где как работает в иерархии джанговских generic views (imho - мусорную информацию), уделили этому часть своего времени и сил - а выигрыш-то в чем? Кода-то больше получается.
Вот это разве не ад (пример из документации)?
class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
def render_to_response(self, context):
# Look for a 'format=json' GET argument
if self.request.GET.get('format','html') == 'json':
return JSONResponseMixin.render_to_response(self, context)
else:
return SingleObjectTemplateResponseMixin.render_to_response(self, context)
Решение с декоратором или наследником TemplateResponse будет по размеру короче (тут еще код JSONResponseMixin не приведен), при этом оно будет еще и более общим, его будет легче использовать повторно (ничего не будет завязано на конкретную иерархию - тут все привязывается к SingleObjectTemplateResponseMixin, например).
Ну вот например, топик сейчас в django-developers обсуждают:
https://groups.google.com/forum/?fromgroups=#!topic/django-developers/7c7aI-slGNc
Вместо того, чтоб решить конкретную задачу и написать несложную логику в функции, CBV заставили в том топике людей решают какие-то странные проблемы, выискивать, какой бы метод переопределить среди всей иерархии (оказалось, что такого метода нет из-за того, в какой последовательности super вызывается). Предлагают добавить еще больше хуков в базовые классы (чтоб разбираться и читать это стало еще сложнее?).
Разница между подходами “вьюха на классах” и “вьюха на функциях” - примерно такая же, как “фреймворк” vs “библиотека”. Фреймворк вызывает ваш код (а вы дописываете какие-то штуки в заранее подготовленные места); вы вызываете код из библиотеки. Несмотря на то, что джангу фреймворком называют, она гораздо ближе к библиотеке, чем всякие symfony, и это замечательно.
Это все если не касаться холивара ООП vs ФП и тестирования.
Короче говоря, ничто не мешает по-нормальному организовать вьюхи на функциях, не пряча и не запутывая логику в дополнтельных абстракциях CBV.
Впрочем, сильно негативное отношение у меня к новым generic views только. Вполне допускаю, что сами по себе CBV могут быть полезными и удобными. Можно представить ситуацию, что вот есть какая-то библиотека, и она хочет предоставить возможность расширения своего функционала без изменения своего кода. Вот тут CBV (не generic) могут быть полезными, т.к. классы - это удобный инструмент в этой ситуации. Пользователь библиотеки может переопределил метод, чтоб тот делал чуть другое, подходящее к конкретной задаче. С функциями это тоже можно решить (передав коллбэк), но классы к этому синтаксический сахар предоставляют в виде наследования, они удобнее и привычнее в этой ситуации.
Но в своем коде такая необходимость встречается достаточно редко: нет такого, что вот код и его нельзя трогать, и поэтому заранее позаботимся о том, чтоб можно было его не трогая какую-то задачу решить. Когда нужно - взял да поправил. Смысл в CBV редко когда есть, и уж точно (imho) не нужно их использовать “по умолчанию”, т.к. с ними (imho) код сложнее читать и править-улучшать, мыслительная нагрузка больше.