这是一个令人费解的问题,甚至难以命名,更不用说描述了。我将从基本事实开始,然后给出可能相关的背景信息。
考虑两个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
的实例?
进一步调试代码显示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
代码以添加一个元类,该元类在创建DBRef
类型时检查系统模块,并存储这些模块的ID列表。 fooDBRef
的额外类属性。结果显示,创建bson.dbref.DBRef
时存在的模块集与创建裸site_a
类型时存在的模块集完全不同。一个模块ID与另一个模块ID不同。
一些可能相关的因素:
site_b
和site_a.foo_app.models
)。site_b.bar_app.models
中定义,条形在site_a
中定义。site_b.bar_app
settings.py在INSTALLED_APPS
中有site_a
。site_b.*
处理。sys.modules
时,fooDBRef
中有site_a.*
个模块,但没有bson.dbref.DBRef
个模块。 httpd reload
反之亦然。fooDBRef
之后,错误有时会消失一段时间,并在0-10次尝试中返回。 任何人都可以帮我找出导致bson.dbref.DBRef
与{{1}}不同的原因吗?
答案 0 :(得分:4)
您使用mod_wsgi的嵌入模式还是守护进程模式?如果使用mod_wsgi的守护进程模式,您是将每个站点委派给不同的守护程序进程组,然后又强制应用程序在主Python解释器中运行?
可能是这样的情况,mongodb Python客户端模块可能无法在Python子解释器中正常工作,尤其是当该模块同时在同一进程的不同子解释器中使用时。
因此,您可能必须使用WSGIDaemonProcess / WSGIProcessGroup在单独的守护进程组中运行每个站点,然后使用带有'%{GLOBAL}'参数的WSGIApplicationGroup强制Python主解释器的用户。
请注意,在强制使用两个站点的主解释器时,您不能再使用嵌入模式,也不能让它们都在同一个守护进程组中运行。这就是为什么你需要强制每个人在单独的守护进程组中运行。