Pull to refresh

Comments 12

Мне кажется, имеет смысл ставить вопрос об уместности решения в принципе.

Что делает это штука? Она привязывает к классу модели декоратор, который создает поле 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
база будет знать про новое поле, при интроспекции тоже всё будет ок.
но я бы такое засунул в __metaclass__
Я правильно понимаю логику порождения объекта (как-то уж слишком много условий у Вас)?
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.

Articles