Ricevo il seguente errore sul secondo aggiornamento di una pagina: DetachedInstanceError: l'istanza non è associata a una sessione; operazione di aggiornamento attributo non può procederePython (framework Pyramid) sta conservando i dati tra le richieste e non riesco a capire perché
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>
Il problema sembra essere una condivisione di dati memorizzati nella cache tra le richieste. Il fatto è che si suppone solo per essere nella cache locale (cioè tutto ri-query per la richiesta successiva)
La sezione dedicata del modello è:
<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>
mio DBSession è dichiarato solo una volta, nei modelli .py (se questo fa la differenza):
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Se smetto di caching che la fissa, il che significa che solo bisogno di fare non cache tra le richieste, che non so come fare.
Questa è la mia funzione di 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
E 'anche interessante notare che il meta() la funzione memorizza nella cache anche e non ha lo stesso problema - credo che probabilmente la differenza fondamentale è che si memorizza nella cache una dict di stringhe invece di oggetti ORM.
sto usando pserve di servire mentre sto sviluppando esso (anche se questo fa la differenza)
La soluzione temporanea nel mio codice, utilizzando sqlalchemy.inspect, funziona, ma ho davvero voglia i dati per non persistere (cioè Base._meta_refs dovrebbe essere uguale a Nessuno la prima volta che accedo al 100% delle volte).
Qualcuno ha qualche idea? Se questo viene memorizzato nella cache tra le richieste, sono sicuro che ci sono anche altre cose, e questo è troppo potenziale per un comportamento inaspettato.
Mentre sono tutti per la semplificazione, ho bisogno di tutti i dati tramite query SQL 1 (e non li vogliono a persistere tra le richieste). .. Richiede 4.3 ms avg per recuperare tutte le righe o 3.8 ms avg per recuperarle per un singolo modello, quindi inefficiente se sto recuperando più di un modello che è necessario per la maggior parte delle richieste. Le file sono minuscole, il che fa la differenza in questo. In ogni caso, come andrei a memorizzare i dati nell'oggetto richiesta? Sembra fattibile, ma non riesco a trovare la documentazione per fare qualcosa del genere. –
Non sapevo che fosse necessario MetadataRef per più di un modello durante l'esecuzione di una singola richiesta, ma il mio punto era che il codice è troppo complicato per quello che sembra fare. SQL Query è un ottimo strumento e non ci sono buoni motivi per non usarlo a favore di cicli e filtri "manuali". –
Ad ogni modo, la risposta alla tua domanda è nella primissima frase del mio post originale.Non esitate a trascurare il resto. –