Для решения всех проблем, выраженных в различных существующих ответах, я предлагаю следующий подход: создайте метод, назовите его скажем saving
или modifying
, который является менеджером контекста.Запись в этот метод устанавливает закрытый флаг, который говорит, что модификация выполняется;выход сбрасывает флаги и выполняет сохранение;все модифицирующие методы проверяют флаг и вызывают исключение, если не установлено.Например, при использовании базового класса и метода save
реальные подклассы должны переопределять:
import contextlib
class CarefullyDesigned(object):
def __init__(self):
self.__saving = False
def _save(self):
raise NotImplementedError('Must override `_save`!')
def _checksaving(self):
"Call at start of subclass `save` and modifying-methods"
if not self.__saving: raise ValueError('No saving in progress!')
@contextlib.contextmanager
def saving(self):
if self.__saving: raise ValueError('Saving already in progress!')
self.__saving = True
yield
self._save()
self.__saving = False
Пример использования ...:
class Bar(models.Model, CarefullyDesigned):
def __init__(self, *a, **k):
models.Model.__init__(self, *a, **k)
CarefullyDesigned.__init__(self)
def _save(self):
self._checksaving()
self.save()
def set_foo(self, foo):
self._checksaving()
self.foo = foo
def set_fie(self, fie):
self._checksaving()
self.fie = fie
bar = Bar()
with bar.saving():
bar.set_foo("foobar")
bar.set_fie("fo fum")
Это гарантирует, что пользователь не будетне забудьте вызвать saving
или случайно вызвать его вложенным способом (в этом и состоит цель всех этих исключений), и вызывать save
только один раз, когда группа методов-модификаторов готова, в удобной искажем, довольно естественным образом.