これは、説明するどころか、名前を付けることさえ困難な不可解な問題です。重要な事実から始めて、関連する可能性のある背景情報を示します。
2 つの mongoengine ドキュメント モデルを考えてみましょう。
class Bar(Document):
# ...
# field definitions
# ...
def bar_func(self):
pass # ...or some arbitrary code
class Foo(Document):
bar = ReferenceField(Bar)
以下は、実稼働サーバーで矛盾して生成されます。AttributeError
# 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'
エラーの場所の直前にデバッグ コードを配置するtype(foo.bar)
と、文字列として評価すると<class 'bson.dbref.DBRef'>
. 明らかに a には属性DBRef
がありませんが、のインスタンスではなく a が返されるのはなぜですか?bar_func
DBRef
Bar
ReferenceField.__get__
さらにデバッグ コードを実行すると、 の関数で次の条件が失敗していることがわかりますmongoengine/fields.py
。
if isinstance(value, (pymongo.dbref.DBRef)):
value = _get_db().dereference(value)
しかし(pymongo.dbref.DBRef)
、実際bson.dbref.DBRef
には と同じように見えますtype(foo.bar)
。なぜisinstance
失敗するのですか?
これは物事が本当に奇妙になるところです:
id(type(foo.bar)) == id(bson.dbref.DBRef) # <-- Evaluates to False!
つまり、直接参照して得られるものtype(foo.bar)
とは異なります。 実際、これら 2 つの型を調べると、関数とプロパティの異なるメモリ位置が示されます。bson.dbref.DBRef
bson.dbref.DBRef
__dict__
注:type(foo.bar)
fooDBRef
によって参照される型と区別するために、便宜上、以下では によって返される型と呼びますbson.dbref.DBRef
。
さらにデバッグするためにDBRef
、型の作成時にシステム モジュールを検査するメタクラスを追加するようにコードを変更しDBRef
、それらのモジュールの ID のリストを の追加のクラス属性に格納しますDBRef
。結果は、が作成されたときに存在するモジュールのセットが、ベアタイプが作成されたときに存在するモジュールのセットとfooDBRef
は完全に異なることを示しています。bson.dbref.DBRef
一方のすべてのモジュール ID は、もう一方のすべてのモジュール ID とは異なります。
関連する可能性のある要因:
- このエラーが発生するサーバーは、Apache で mod_wsgi を実行しています。
- サーバーは、wsgi の下で 2 つの異なる Django サイトを実行します (それら
site_a
を および と呼びますsite_b
)。 - Foo は で定義され
site_a.foo_app.models
、Bar は で定義されていsite_b.bar_app.models
ます。 site_a
settings.py にsite_b.bar_app
はINSTALLED_APPS
.- エラーを生成する要求は によって処理され
site_a
ます。 - が作成されたときに
site_b.*
モジュールがありましたが、モジュールはありませんでした。については逆です。sys.modules
fooDBRef
site_a.*
bson.dbref.DBRef
- エラーが発生した後、
httpd reload
しばらくの間エラーが解消され、0 ~ 10 回の試行で元に戻ることがあります。
fooDBRef
との違いの原因を突き止めるのを手伝ってくれる人はいbson.dbref.DBRef
ますか?