Раньше я работал над проектом, который включал версию шаблона Уникальный объект . Этот конкретный код был написан не мной, и в поисках информации я нашел оригинальный рецепт. Я пытаюсь понять это, но некоторые детали приходят мне в голову.
Реализация, которая была сделана в проекте, очень похожа на ту, что представлена в вики, но вместо _unique
, get_unique
реализован как метод класса общей базовой модели. Он принимает произвольные параметры и делает почти то же, что _unique
делает в вики, но определившись с параметрами hashfunc
, queryfunc
и constructor
:
class Model(Base):
@classmethod
def get_unique(cls, session, **kwargs):
"""Get or create an instance based on unique values.
"""
cache = getattr(session, '_unique_cache', None)
if cache is None:
session._unique_cache = cache = {}
key = (cls, tuple(kwargs.items()))
o = cache.get(key)
if o is not None and was_deleted(o):
o = None
if o is None:
with session.no_autoflush:
o = session.query(cls).filter_by(**kwargs).first()
if o is None:
o = cls(**kwargs)
session.add(o)
cache[key] = o
return o
Мне известны некоторые предостережения эта реализация, будучи одним из наиболее важных фактов, что порядок kwargs имеет значение для построения key
. Мои вопросы:
Есть ли основания заключать запрос в контекст no_autoflush
? Что будет не так, если облако программистов решит, вызывать get_unique
с autoflush
или без него? Рецепт вики также выполняет запрос с no_autoflush
, и мне интересно, ускользает ли мое понимание от понимания.
Почему объекты кэшируются? Я не вижу смысла кэшировать объекты, когда сессия уже выполняет аналогичную задачу и знает, когда нужно повторно извлечь объекты из базы данных.
Поэтому неправильно со следующей реализацией, которая не использует кеш и позволяет программисту решить, требуется ли контекст no_autoflush
?
class Model(Base):
@classmethod
def get_unique(cls, session, **kwargs):
"""Get or create an instance based on unique values.
"""
o = session.query(cls).filter_by(**kwargs).first()
if o is None:
o = cls(**kwargs)
session.add(o)
return o