Предположим, что класс имеет метод, который изменяет, это - внутренности. Тот вызов метода должен экономить на себе прежде, чем возвратиться, или сохранение нужно оставить вызывающей стороне явно сохранить после того, как метод изменения назвали?
Пример:
Явно вызов сохраняет:
class Bar(models.Model):
def set_foo(self, foo):
self.foo = foo
bar = Bar()
bar.set_foo("foobar")
bar.save()
или разрешение метода звонить сохраняет:
class Bar(models.Model):
def set_foo(self, foo):
self.foo = foo
self.save()
bar = Bar()
bar.set_foo("foobar")
Я работаю с django, но я задавался вопросом, была ли лучшая практика в django или в целом для этой ситуации.
Пользователь вашего API может забыть вызвать .save (), а затем ошибиться. Так что я думаю, что лучше позвонить и сэкономить для него. Для случаев, подобных тем, которые упоминает Даслч, если это имеет смысл, вы можете определить:
def set_foo(self, foo, skip_save=False):
self.foo = foo
if not skip_save:
self.save()
, чтобы пользователь мог, если он желает (и явно заявляет об этом), избежать сохранения.
Пользователь вашего API может захотеть сделать несколько изменений, сохранение объекта после каждого изменения - это не очень хорошо, так что нет, не вызывайте save в вашем методе.
На самом деле, я согласен и с Офри, и с Даслчем ... в зависимости от того, какой сегодня день недели. Если это всего лишь одна из многих процедур модификации, которые вы можете применить к конкретному объекту, то будет довольно дорого, если каждая из них будет делать свое собственное сохранение. С другой стороны, если это редкое, самодостаточное событие, вы хотите сохранить, потому что это может быть неочевидно для вызывающего абонента (т. Е. Для кого-то, кроме вы , что это необходимо сделать. .
Например, тегирование событий (которые в любом случае используют ManyToMany) не должно требовать дополнительного save () со стороны программистов.
Для решения всех вопросов, выраженных в различных существующих ответах, я предлагаю следующий подход: сделайте метод, назовите его, скажем, сохранение
или изменение
, который является менеджером контекста. При входе в этот метод устанавливается приватный флаг, который говорит, что идет модификация; при выходе флаг сбрасывается и выполняется сохранение; все модифицирующие методы проверяют флаг и вызывают исключение, если он не установлен. Например, используя базовый класс и метод 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")
Это гарантирует, что пользователь не забудет вызвать save
и не вызовет его случайно вложенным способом (именно для этого и предназначены все эти исключения), а вызовет save
только один раз, когда группа модифицирующих методов будет завершена, удобным и, я бы сказал, довольно естественным способом.