C'est un problème déroutant qui est difficile à nommer, et encore moins à décrire. Je vais commencer par les faits essentiels et ensuite donner ce que les informations de base pourraient être pertinentes.Weirdness avec mongoengine ReferenceField
Tenir compte deux modèles de documents mongoengine:
class Bar(Document):
# ...
# field definitions
# ...
def bar_func(self):
pass # ...or some arbitrary code
class Foo(Document):
bar = ReferenceField(Bar)
Ce qui suit est incohérente produisant un AttributeError
sur notre serveur de production:
# Assume foo_id references a valid Foo document in Mongo
# and that its 'bar' reference is to a valid Bar document.
foo = Foo.objects.with_id(foo_id)
foo.bar.bar_func() # <-- AttributeError on 'bar_func'
Si je place le code de débogage juste avant l'emplacement de l'erreur , l'évaluation type(foo.bar)
en tant que chaîne produit <class 'bson.dbref.DBRef'>
. Évidemment, un DBRef
n'a pas d'attribut bar_func
, mais pourquoi un DBRef
est-il renvoyé au lieu d'une instance de Bar
?
autre code de débogage montre que la condition suivante échoue dans la fonction ReferenceField.__get__
dans mongoengine/fields.py
:
if isinstance(value, (pymongo.dbref.DBRef)):
value = _get_db().dereference(value)
Mais (pymongo.dbref.DBRef)
est en fait bson.dbref.DBRef
, qui semble être le même que type(foo.bar)
! Pourquoi isinstance
échoue?
C'est là que les choses se vraiment bizarre:
id(type(foo.bar)) == id(bson.dbref.DBRef) # <-- Evaluates to False!
En d'autres termes, type(foo.bar)
est un autre bson.dbref.DBRef
que celle obtenue en faisant référence bson.dbref.DBRef
directement. En fait, l'inspection du __dict__
de ces deux types montre différents emplacements de mémoire pour leurs fonctions et leurs propriétés.
Note: Je vais appeler le type retourné par type(foo.bar)
fooDBRef
pour des raisons pratiques ci-dessous, pour le distinguer du type référencé par bson.dbref.DBRef
.
Pour déboguer plus loin, je modifié le code DBRef
ajouter une métaclasse qui inspecte les modules du système au moment du type DBRef
est créé, et stocke une liste des ID de ces modules dans un attribut de classe supplémentaire de DBRef
. Les résultats montrent que l'ensemble des modules existants lorsque fooDBRef
est créé est entièrement distinct à partir de l'ensemble des modules existant lorsque le type bson.dbref.DBRef
nu est créé. Tous les ID de module pour un sont différents de tous les ID de module pour l'autre.
Certains facteurs éventuellement pertinents:
- Le serveur sur lequel cette erreur se produit Runs mod_wsgi sous Apache.
- Le serveur exécute deux sites Django différents sous wsgi (appelez-les
site_a
etsite_b
). - Foo est défini dans
site_a.foo_app.models
et Bar est défini danssite_b.bar_app.models
. site_a
paramètres.py asite_b.bar_app
dansINSTALLED_APPS
.- Les demandes qui produisent l'erreur sont traitées par
site_a
. - Il y avait
site_b.*
modules danssys.modules
lorsquefooDBRef
a été créé, mais passite_a.*
modules. L'inverse est vrai pourbson.dbref.DBRef
. - Après un
httpd reload
l'erreur disparaît parfois pendant un petit moment, et retourne parfois dans les 0-10 tentatives.
Quelqu'un peut-il me aider à comprendre ce qui est à l'origine fooDBRef
être différent de bson.dbref.DBRef
?
Nous utilisions le mode intégré. Je suis passé en mode démon, en ajoutant les directives WSGIDaemonProcess, WSGIProcessGroup et WSGIApplicationGroup aux entrées VirtualHost et la directive WSGISocketPrefix au niveau racine de la configuration. Et ça a l'air d'avoir marché! Au moins, l'erreur ne s'est pas encore produite, et normalement elle aurait eu lieu à ce stade. Je vais attendre un jour ou deux pour m'assurer qu'il est parti et ensuite accepter la réponse. Merci pour l'aide! – Alanyst
Je suis satisfait que cela fonctionne maintenant. Merci encore. – Alanyst