Comments 12
Мне кажется, имеет смысл ставить вопрос об уместности решения в принципе.
Что делает это штука? Она привязывает к классу модели декоратор, который создает поле enable со значением по умолчанию, распространяющимся на все объекты модели. Тут я придерусь вовсе не к оформлению синтаксиса по PEP а к тому, что член класса не стоит называть как действие, также как и метод класс не надо называть как объект данных. a = zzz.enabled — это ок. zzz.enable(), a = zzz.is_enabled() — тоже. Наоборот — некорректно. У тела есть атрибут нога и есть метод ходить, но не наоборот.
По сути это конструктор класса, но база данных не будет знать что конструктор поменялся, а основная задача ОРМ — обеспечивать репрезентацию данных в виде объектов и наоборот.
Как это решение поведет себя при использовании системы миграций схемы или данных? Как будет работать при интроспекции моделей? Как оно будет вести себя в queryset-ах? Пока в голове нет точного ответа на эти вопросы, такие решения — мина замедленного действия.
Джанговский ОРМ это большой сложный продукт с которым напрямую связывается много 3-rd party и который имеет много сложных нюансов в поведении. Чем дальше я с ним работаю, тем реже у меня возникает желание хоть как-то вмешиваться в его работу, переносить туда логику, использовать наследование или атипичные члены и так в нем присутствует немало сюрпризов.
И я вообще не вижу проблемы. То есть действительно сложно создать несколько или несколько десятков классов с одинаковым полем и разным значением по умолчанию? Код должен быть понятным и предсказуемым в поведении, и только после этого можно говорить о DRY и прочих необязательных вещах, а также попытках выстрелить себе в левую пятку через правое плечо. (путем объединения mixin и декораторов в одну структуру, например)
Декораторы для вьюшек вроде login_required уместны, так как вьюшка — это метод, прямая палка с определенным входом и выходом, в перехвате которых нет ничего сложного или непонятного.
К классу модели в принципе можно цеплять декораторы но с методами, которые полезут в данные и что-то на основании их ответят, или что-то расскажут о самом классе, ну например геттер is_enabled() который проверит поле enable и выдаст его значение для конкретного объекта. Хотя смысла в этом маловато.
Что делает это штука? Она привязывает к классу модели декоратор, который создает поле enable со значением по умолчанию, распространяющимся на все объекты модели. Тут я придерусь вовсе не к оформлению синтаксиса по PEP а к тому, что член класса не стоит называть как действие, также как и метод класс не надо называть как объект данных. a = zzz.enabled — это ок. zzz.enable(), a = zzz.is_enabled() — тоже. Наоборот — некорректно. У тела есть атрибут нога и есть метод ходить, но не наоборот.
По сути это конструктор класса, но база данных не будет знать что конструктор поменялся, а основная задача ОРМ — обеспечивать репрезентацию данных в виде объектов и наоборот.
Как это решение поведет себя при использовании системы миграций схемы или данных? Как будет работать при интроспекции моделей? Как оно будет вести себя в queryset-ах? Пока в голове нет точного ответа на эти вопросы, такие решения — мина замедленного действия.
Джанговский ОРМ это большой сложный продукт с которым напрямую связывается много 3-rd party и который имеет много сложных нюансов в поведении. Чем дальше я с ним работаю, тем реже у меня возникает желание хоть как-то вмешиваться в его работу, переносить туда логику, использовать наследование или атипичные члены и так в нем присутствует немало сюрпризов.
И я вообще не вижу проблемы. То есть действительно сложно создать несколько или несколько десятков классов с одинаковым полем и разным значением по умолчанию? Код должен быть понятным и предсказуемым в поведении, и только после этого можно говорить о DRY и прочих необязательных вещах, а также попытках выстрелить себе в левую пятку через правое плечо. (путем объединения mixin и декораторов в одну структуру, например)
Декораторы для вьюшек вроде login_required уместны, так как вьюшка — это метод, прямая палка с определенным входом и выходом, в перехвате которых нет ничего сложного или непонятного.
К классу модели в принципе можно цеплять декораторы но с методами, которые полезут в данные и что-то на основании их ответят, или что-то расскажут о самом классе, ну например геттер is_enabled() который проверит поле enable и выдаст его значение для конкретного объекта. Хотя смысла в этом маловато.
Про название атрибута абсолютно с вами согласен. Дальше текст пытаюсь осмыслить. Простите, сегодня мало спал может из-за этого проблемы в понимании вашей мысли. Но в любом случае за критику спасибо.
Вычленил 4 мысли, поправьте если чего недопонял:
- Атрибут не надо называть глаголом
+1. Я бы еще не стал называть параметр, у которого назначение — принимать значение по-умолчанию «status». Без чтения коментариев не понять. Другое дело если назвать «default» (не зря же дальше параметр передается именно с таким именем). - Создатели джанго — из особенной касты — им можно использовать метаклассы и прочие нетривиальные конструкции. А самим лучше туда не соваться. На худой конец чуть-чуть можно, если ты разработчик «3-rd party».
Утрировал конечно, но все же: чем пользователь фреймворка хуже? - Чувствую возможные сайд-эффекты. В чем именно проблема не наю, но чувствую что добром не кончится.
Ну можно конечно всю жизнь себя ограничивать в использовании конструкций сложнее @login_required, но зачем? :)
Проверить что новая моедль ведет себя нормально на самом деле не очень трудно. - Что сложно N-цать раз прописать одинаковые атрибуты и менеджеры?
Если из 200 моделей в проекте найдется парочка вот таких — да, лучше дописать явно.
А вот если из 200 моделей в 150 встречается добавление этого enabled, и что еще хуже для каждого queryset дописывается filter(enabled=True) — извините, но это уже плохой код. И попытка его улучшить не взирая сложность джанговского ORM-а — по-моему весьма похвальна.
> Создатели джанго — из особенной касты — им можно использовать метаклассы и прочие нетривиальные конструкции. А самим лучше туда не соваться. На худой конец чуть-чуть можно, если ты разработчик «3-rd party».
> Утрировал конечно, но все же: чем пользователь фреймворка хуже?
Метаклассы в принципе ок. Это штатный инструмент, правда с ними связана одна неприятная особенность — они не поддерживаются south, обещают поправить в неопределенном будущем, когда south будет включен в джанговский пекадж, но работу без него представить сложно.
Но не надо путать метаклассы с подобными конструкциями. Разработчики 3rd-party как раз будут рассчитывать на то, что ваши модели используются достаточно стандартно.
Сейчас быстро попробовал это решение на тестовом проекте с заглушкой вместо кастом-менеджера — в качестве декоратора ведет себя достаточно адекватно и интроспекция отрабатывает адекватно. Так что автору плюсов в карму, на практике декораторы оказались хорошей заменой абстрактным классам.
Попытка использования подобного паттерна в качестве примеси — откровенный фейл, фабрика нежизнеспособна и честно говоря даже неинтересно разбираться как сделать ее таковой, сущность которая пытается вести себя и как класс и как функция — это нездоровый паттерн.
Я бы вообще выкинул вариант с поведением в качестве mixin, так как практика использования декораторов для класса модели сама по себе интересна. В крайнем случае нет особой сложности написать дополнительно нормальный абстрактный класс для таких целей.
Фиксы:
enbaled >> enabled
false (в примерах) >> False
> Утрировал конечно, но все же: чем пользователь фреймворка хуже?
Метаклассы в принципе ок. Это штатный инструмент, правда с ними связана одна неприятная особенность — они не поддерживаются south, обещают поправить в неопределенном будущем, когда south будет включен в джанговский пекадж, но работу без него представить сложно.
Но не надо путать метаклассы с подобными конструкциями. Разработчики 3rd-party как раз будут рассчитывать на то, что ваши модели используются достаточно стандартно.
Сейчас быстро попробовал это решение на тестовом проекте с заглушкой вместо кастом-менеджера — в качестве декоратора ведет себя достаточно адекватно и интроспекция отрабатывает адекватно. Так что автору плюсов в карму, на практике декораторы оказались хорошей заменой абстрактным классам.
Попытка использования подобного паттерна в качестве примеси — откровенный фейл, фабрика нежизнеспособна и честно говоря даже неинтересно разбираться как сделать ее таковой, сущность которая пытается вести себя и как класс и как функция — это нездоровый паттерн.
Я бы вообще выкинул вариант с поведением в качестве mixin, так как практика использования декораторов для класса модели сама по себе интересна. В крайнем случае нет особой сложности написать дополнительно нормальный абстрактный класс для таких целей.
Фиксы:
enbaled >> enabled
false (в примерах) >> False
база будет знать про новое поле, при интроспекции тоже всё будет ок.
но я бы такое засунул в __metaclass__
но я бы такое засунул в __metaclass__
Я правильно понимаю логику порождения объекта (как-то уж слишком много условий у Вас)?
P.S.
Раз уж Вы спросили. Каноническое именование декоратов классов, как и фабрики mixin-ов — с маленькой буквы.
Ну и пару комментарев бы поправил:
:param cls: class that would updates — мне кажется тут нужен пассивный залог
:param set_manager: sets is EnableManager is required — опечатка, первый «is» -> «if»
if cls and mixin:
raise DecoratorMixinException
if mixin:
return Class
elif cls:
decorator(cls)
else:
decorator
P.S.
Раз уж Вы спросили. Каноническое именование декоратов классов, как и фабрики mixin-ов — с маленькой буквы.
Ну и пару комментарев бы поправил:
:param cls: class that would updates — мне кажется тут нужен пассивный залог
:param set_manager: sets is EnableManager is required — опечатка, первый «is» -> «if»
У модели можно задать __metaclass__ вкотором добавить поля и т.п.
Погодите, а почему нельзя было просто написать модель, от которой унаследоваться позже?
Sign up to leave a comment.
Чуть-чуть «извращений» над моделями django