怪诞与mongoengine ReferenceField
这是一个令人费解的问题,这是很难甚至名字,更不用说形容。我将从基本事实开始,然后给出可能相关的背景信息。怪诞与mongoengine ReferenceField
考虑两个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
类型时存在的模块集合完全不同。其中一个的所有模块ID与另一个的所有模块ID不同。
一些可能相关的因素:
- 上Apache下出现此错误运行mod_wsgi的服务器。
- 服务器在wsgi下运行两个不同的Django站点(称它们为
site_a
和site_b
)。 - foo是
site_a.foo_app.models
定义和酒吧在site_b.bar_app.models
定义。 -
site_a
设置。py在INSTALLED_APPS
中有site_b.bar_app
。 - 产生错误的请求由
site_a
处理。 - 模块
sys.modules
fooDBRef
创建时,但没有site_a.*
模块。bson.dbref.DBRef
的情况正好相反。 - 的
httpd reload
错误后有时会消失一小会儿,和0-10次尝试内的某个时候返回。
谁能帮我找出是什么原因造成fooDBRef
从bson.dbref.DBRef
不同?
您是否使用嵌入模式或mod_wsgi的守护进程模式?如果使用mod_wsgi的守护进程模式,您是将每个站点委派给不同的守护进程进程组,然后又强制应用程序在主Python解释器中运行?
这可能是MongoDB的Python客户端模块可能并不在Python子口译正常工作,特别是当模块在同一进程中的一个不同的子解释器使用在相同时间的情况下。
所以,你可以在使用WSGIDaemonProcess/WSGIProcessGroup运行在独立的守护程序组中的每个站点,然后使用WSGIApplicationGroup用“%{}全球”的说法强迫的Python解释器为主的用户。
注意,迫使使用主解释的时候为这两个网站,你可以不再使用嵌入模式,或让他们在同一个后台进程组中的两个运行。因此,为什么你需要强制每个运行在单独的守护进程组中。
我们使用嵌入模式。我切换到守护进程模式,加入WSGIDaemonProcess,WSGIProcessGroup和WSGIApplicationGroup指示到虚拟主机的条目,并且WSGISocketPrefix指令到配置的根级别。它似乎有效!至少,这个错误还没有发生,而且通常情况下它会有这个问题。我将等待一天左右,确保它消失,然后接受答案。谢谢您的帮助! – Alanyst
我很满意它现在的作品。再次感谢。 – Alanyst