这是一个令人费解的问题,甚至难以命名,更不用说描述了。我将从基本事实开始,然后给出可能相关的背景信息。
考虑两个 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'>
. 显然 aDBRef
没有bar_func
属性,但为什么DBRef
要返回 a 而不是 的实例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)
的不同 。事实上,检查这两种类型会显示它们的功能和属性的不同内存位置。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 下运行两个不同的 Django 站点(调用它们
site_a
和site_b
)。 - Foo 定义在 中
site_a.foo_app.models
,Bar 定义在site_b.bar_app.models
. site_a
settings.pysite_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
吗?