Che*_*art 5 python caching sqlalchemy python-2.7 chameleon
我在第二次刷新页面时遇到以下错误:DetachedInstanceError:实例未绑定到Session; 属性刷新操作无法继续
DetachedInstanceError: Instance <MetadataRef at 0x107b2a0d0> is not bound to a Session; attribute refresh operation cannot proceed
- Expression: "result.meta_refs(visible_search_only=True)"
- Filename: ... ects/WebApps/PYPanel/pypanel/templates/generic/search.pt
- Location: (line 45: col 38)
- Source: ... meta_ref result.meta_refs(visible_search_only=True)" tal:omi ...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Arguments: repeat: {...} (0)
renderer_name: templates/home.pt
models: <list - at 0x1069e4d88>
results: <list - at 0x107c30d40>
renderer_info: <RendererHelper - at 0x1069b5650>
active_models: <list - at 0x107b69050>
query:
pagination: <NoneType - at 0x104dd5538>
req: <Request - at 0x107b4e690>
title: <NoneType - at 0x104dd5538>
generic: <NoneType - at 0x104dd5538>
request: <Request - at 0x107b4e690>
context: <RootFactory - at 0x107b12090>
page: 1
view: <Page - at 0x107b128d0>
Run Code Online (Sandbox Code Playgroud)
问题似乎是在请求之间共享缓存数据.问题是它只应该在本地缓存(即重新查询下一个请求的所有内容)
模板的相关部分是:
<div tal:repeat="meta_ref result.meta_refs(visible_search_only=True)" tal:omit-tag="True">
<div tal:define="meta result.meta(meta_ref.key, None)" tal:condition="meta is not None">
<div>${meta_ref.name} = ${meta}</div>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
我的DBSession只在models.py中声明一次(如果这有所不同):
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Run Code Online (Sandbox Code Playgroud)
如果我停止缓存它修复它,这意味着我只需要使它不在请求之间缓存,我不知道该怎么做.
这是我的meta_refs函数:
def meta_refs(self, visible_only=False, visible_search_only=False):
model = self.__class__.__name__
if Base._meta_refs is None:
Base._meta_refs = {}
try:
for result in DBSession.query(MetadataRef):
if result.model not in Base._meta_refs:
Base._meta_refs[result.model] = []
Base._meta_refs[result.model].append(result)
except DBAPIError:
pass
if model not in Base._meta_refs:
return []
results = []
for result in Base._meta_refs[model]:
#@TODO: Remove temporary workaround
if inspect(result).detached:
Base._meta_refs = None
return self.meta_refs(visible_only, visible_search_only)
#END of workaround
if visible_only and result.visible is False:
continue
if visible_search_only and result.visible_search is False:
continue
results.append(result)
return results
Run Code Online (Sandbox Code Playgroud)
值得注意的是,meta()函数也缓存并且没有相同的问题 - 我认为关键的区别在于它缓存字符串而不是ORM对象.
我正在开发它时使用pserve来服务它(如果这有所不同的话)
我的代码中的临时解决方法,使用sqlalchemy.inspect,确实有效,但我真的只是希望数据不会持久存在(即,我第一次100%访问它时,Base._meta_refs应该等于None).
有人有主意吗?如果这是在请求之间缓存,我确信还有其他东西也是如此,这对于意外行为来说太可能了.
假设 Base 是一个类,您可以使用它的_meta_refs属性来存储MetadataRef实例并有效地在请求之间保留它们。
如果在许多情况下像缓存一样工作的 SQLAlchemy 会话标识映射还不够,您可以使用请求对象来存储这些对象,并知道它们只会在请求的生命周期内持续存在。
我会简化meta_refs方法如下:
@classmethod
def meta_refs(cls, visible_only=False, visible_search_only=False):
q = DBSession.query(MetadataRef).filter(MetadataRef.model==cls.__name__)
if visible_only:
q = q.filter(MetadataRef.visible==True)
if visible_search_only:
q = q.filter(MetadataRef.visible_search==True)
# It might be worth returning q rather than q.all()
return q.all()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
316 次 |
| 最近记录: |