gpt4 book ai didi

python - SQLAlchemy:懒惰 ='raise' 提示字段,即使它们已加载

转载 作者:行者123 更新时间:2023-12-05 05:55:34 24 4
gpt4 key购买 nike

我们使用 sqlalchemy 的异步版本,我们需要预先加载每个关系(延迟加载不适用于异步)。因此,对于我们模型中的每个关系,我们都设置了 lazy='raise'。问题是它似乎在引发错误方面过于激进。考虑以下单元测试:

async def test_user_group_self_allowed(self):
privilege = await self.db.get(Privilege, 1, [joinedload(Privilege.role)])
options = [joinedload(Item.privileges).joinedload(Privilege.role), joinedload(Item.item_group)]
item = await self.db.get(Item, 1, options)
item.privileges.append(privilege)
await (self.db.commit())

options = [joinedload(User.user_groups).joinedload(UserGroup.privileges), joinedload(User.privileges)]
user = await self.db.get(User, 1, options)
user.privileges = []
item = await self.db.get(Item, 1, [joinedload(Item.privileges).joinedload(Privilege.role), joinedload(Item.item_group)])
user_group = await self.db.get(UserGroup, 1, [joinedload(UserGroup.organization)])
print('why?????', user_group.organization)
self.assertTrue(await self.helper.is_authorized(self.db, user, 'edit', user_group))

注意打印,它会导致以下错误:

Traceback (most recent call last):


File "/usr/lib/python3.9/unittest/async_case.py", line 65, in _callTestMethod
self._callMaybeAsync(method)
File "/usr/lib/python3.9/unittest/async_case.py", line 88, in _callMaybeAsync
return self._asyncioTestLoop.run_until_complete(fut)
File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/usr/lib/python3.9/unittest/async_case.py", line 102, in _asyncioLoopRunner
ret = await awaitable
File "/src/backend-core/backend_core/tests/authorization.py", line 206, in test_user_group_self_allowed
print('why?????', user_group.organization)
File "/usr/local/lib/python3.9/dist-packages/sqlalchemy/orm/attributes.py", line 481, in __get__
return self.impl.get(state, dict_)
File "/usr/local/lib/python3.9/dist-packages/sqlalchemy/orm/attributes.py", line 926, in get
value = self._fire_loader_callables(state, key, passive)
File "/usr/local/lib/python3.9/dist-packages/sqlalchemy/orm/attributes.py", line 962, in _fire_loader_callables
return self.callable_(state, passive)
File "/usr/local/lib/python3.9/dist-packages/sqlalchemy/orm/strategies.py", line 836, in _load_for_state
self._invoke_raise_load(state, passive, "raise")
File "/usr/local/lib/python3.9/dist-packages/sqlalchemy/orm/strategies.py", line 795, in _invoke_raise_load
raise sa_exc.InvalidRequestError(
sqlalchemy.exc.InvalidRequestError: 'UserGroup.organization' is not available due to lazy='raise'

如您所见,它提示组织没有被急切加载,而我明确地将其包含在带有 joinedload 的选项中。现在我们可以通过将用户查询的选项更改为:

options = [joinedload(User.user_groups).joinedload(UserGroup.privileges), joinedload(User.privileges), joinedload(User.user_groups).joinedload(UserGroup.organization)]

(与之前相同的选项,只是我们为用户添加了一个joinedload -> UserGroups -> Organization)

这会使错误消失,一切都恢复正常。现在我的问题是,为什么它一开始就提示这个?我访问 user_group.organization 而不是 user.user_groups[x].organization.. 我不知道这些查询到底是如何工作的,但我不仅有以这种方式编写过多的联合负载,我认为这也会导致不必要的查询。

最佳答案

事实证明,.get 缓存的内容超出了我的预期。不仅是主要实体(在本例中为 usergroup),还有通过 joinedload(user.user_group.organization)加载的内容。因此,这意味着直接获取组织不会覆盖来自 user.user_group.organizationusergroup.organization 的缓存。但是可以这样做db.get(Organization, 1, populate_existing=True) 将再次检索实体并更新缓存。

来自docs :
如果给定的主键标识符存在于本地身份映射中,则直接从此集合返回对象并且不会发出 SQL,除非对象已标记为完全过期....
...
populate_existing – 使方法无条件地发出 SQL 查询并使用新加载的数据刷新对象,无论对象是否已经存在。

正如它所说,另一种方法是使对象过期,阅读更多相关信息 here

关于python - SQLAlchemy:懒惰 ='raise' 提示字段,即使它们已加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69448674/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com