【发布时间】:2011-12-07 23:16:45
【问题描述】:
这是一个令人费解的问题,甚至难以命名,更不用说描述了。我将从基本事实开始,然后提供可能相关的背景信息。
考虑两个 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'>。显然DBRef 没有bar_func 属性,但是为什么返回DBRef 而不是Bar 的实例?
进一步的调试代码显示,mongoengine/fields.py 中的 ReferenceField.__get__ 函数出现以下情况失败:
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_asettings.py 在INSTALLED_APPS中有site_b.bar_app。 - 产生错误的请求由
site_a处理。 - 在创建
fooDBRef时,sys.modules中有site_b.*模块,但没有site_a.*模块。bson.dbref.DBRef则相反。 - 在
httpd reload之后,错误有时会消失一段时间,然后在 0-10 次尝试后返回。
谁能帮我找出导致fooDBRef 与bson.dbref.DBRef 不同的原因?
【问题讨论】:
标签: python django mod-wsgi mongoengine