В моем случае запросы к базовой базе данных довольно дороги, поэтому мы пытаемся сохранять запросы к базе данных, где это возможно.
Вот упрощенная база данных, которую я буду использовать для примеров:
items_table = Table("invtypes", gdata_meta,
Column("typeID", Integer, primary_key = True),
Column("typeName", String, index=True),
Column("groupID", Integer, ForeignKey("invgroups.groupID"), index=True))
mapper(Item, items_table,
properties = {"group" : relation(Group, backref = "items"),
"ID" : synonym("typeID"),
"name" : synonym("typeName")})
groups_table = Table("invgroups", dbmetadata,
Column("groupID", Integer, primary_key = True),
Column("groupName", String))
mapper(Group, groups_table,
properties = {"ID" : synonym("groupID"),
"name" : synonym("groupName")})
Затем мы выбираем некоторый объект Item и одну из групп:
engine = create_engine("sqlite:///<path-to-db>", echo=True)
Session = sessionmaker(bind=engine)
session = Session()
itm = session.query(Item).get(11184) #1
grp = session.query(Group).get(831) #2
В данном конкретном случае itm.groupID = 831, поэтому группа itm уже загружена в память. Тем не менее:
* * 1010
SQLAlchemy указывает, что свойство / отношение группы 'itm' выгружено. Однако в этом случае при доступе к ней не выдаются запросы к базовой базе данных, поскольку она уже загружена в строке с меткой # 2. После первого доступа он больше не помечается как выгруженный.
Теперь давайте закончим с примером выше и поговорим в общем. При доступе к свойству группы объекта Item на группу с запрошенным идентификатором можно уже ссылаться где-то (т. Е. Уже сопоставлено в текущем сеансе) или существовать только в базовой базе данных.
Моя текущая цель - найти способ надежно определить, загружен ли уже в память Item с данным идентификатором и свойством / отношением 'group' ИЛИ выполнять загрузку, затем доступ к itm.group, и если SQLAlchemy не может что-то извлечь из него его объектной карты и собирается выполнить запрос к базовой базе данных - перехватить его и выполнить другой запрос к базе данных. Это должно гарантировать, что для загрузки всего, что мне нужно, требуется не более одного запроса к базе данных (с энергичной загрузкой в случае необходимости) или ноль запросов, если все уже загружено.
Как я описал в одном из приведенных выше абзацев, attribute.instance_state (). Unloaded не является надежным способом. Он не обнаруживает фактическое загруженное состояние свойства / отношения, к которому никогда не обращались.
Я планирую использовать его для оптимизации запросов, которые требуют активной загрузки (а именно, в случаях, когда все запрошенные объекты уже загружены, что часто случается в моих случаях, и когда эти запросы достаточно различны, чтобы кэш запросов не работал для них).