2014-07-14 45 views
5

我得到一個頁面的第二刷新以下錯誤: DetachedInstanceError:實例沒有被綁定到會話;屬性刷新操作無法繼續的Python(金字塔架構)是持續的請求之間的數據和我想不通爲什麼

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> 

這個問題似乎是請求之間緩存數據的一些共享。問題是,它應該只是一個本地緩存(即重新查詢一切爲了下一個請求)

模板的相關部分是:

 <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> 

我DBSession只聲明瞭一次,在模型的.py(如果有差別):

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) 

如果我停下緩存它修復它,這意味着我只需要提出要求,我不知道該怎麼辦之間就沒有緩存。

這是我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 

另外值得一提的是,元()函數還緩存,並沒有同樣的問題 - 我想可能是關鍵的區別是它一個緩存字符串的字典而不是ORM對象。

我使用pserve服務於它,而我正在開發它(如果也有差別)

的臨時解決方法,在我的代碼,使用sqlalchemy.inspect,工作,但我真的只是想數據只是不會持久化(即Base._meta_refs在我第一次訪問它時100%應該等於None)。

任何人有任何想法?如果這是在請求之間緩存的,我相信還有其他的東西也是如此,並且這對於意外行爲來說太有可能了。

回答

3

假設Base是一個類,您可以使用它的_meta_refs屬性來存儲MetadataRef實例並有效地保持它們在請求之間保持不變。

如果SQLAlchemy會話identity map在許多情況下像緩存一樣工作是不夠的,您可以使用請求對象來存儲這些對象,並知道它們只會持續一個請求的生命週期。

而且我要簡化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() 
+0

雖然我所有的簡單化,我需要通過一個SQL語句(不希望他們的請求之間持續存在)中的所有數據。 ..檢索所有行需要4.3ms平均值或平均值爲3.8ms,以便爲單個模型檢索它們,因此如果我檢索多個對大多數請求都必需的模型,則效率低下。行是微小的順便說一句,這有所不同。 無論如何,我會如何將數據存儲在請求對象中?這聽起來是可行的,但我似乎無法找到像這樣的文件。 –

+0

我不知道你服務一次請求時需要MetadataRef不止一個模型,但我的觀點是,你的代碼是什麼,似乎在做太複雜。 SQLAlchemy的查詢是很好的工具,沒有理由避免使用它來支持循環和「手動」過濾。 –

+0

無論如何,你的問題的答案是在我原來的職位的第一句話。請隨時忽略其餘部分。 –

相關問題