问题与DictField在MongoEngine DynamicDocument
我的问题这个职位相匹配的Bountysource:问题与DictField在MongoEngine DynamicDocument
我工作的地方已经用PyMongo 2.6.3/MongoEngine 0.8.7一会儿,我们正在考虑升级到PyMongo 3.2.2/MongoEngine 0.10.6。我下载了这些版本并开始测试它们。我开始遇到一个基于使用DictFields的DynamicDocuments的类。
14:20:20 ERROR nas.data.sync Traceback (most recent call last):
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/nas/data/sync.py", line 1484, in main
14:20:20 ERROR nas.data.sync result = funct(external, syncRecord)
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/nas/data/sync.py", line 456, in syncAsset
14:20:20 ERROR nas.data.sync success = scheduleUpdate(asset, v) and success
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/nas/data/sync.py", line 299, in scheduleUpdate
14:20:20 ERROR nas.data.sync for wu in workunits:
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/queryset.py", line 80, in _iter_results
14:20:20 ERROR nas.data.sync self._populate_cache()
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/queryset.py", line 92, in _populate_cache
14:20:20 ERROR nas.data.sync self._result_cache.append(self.next())
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/base.py", line 1407, in next
14:20:20 ERROR nas.data.sync raw_doc = self._cursor.next()
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/base.py", line 1481, in _cursor
14:20:20 ERROR nas.data.sync self._cursor_obj = self._collection.find(self._query,
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/base.py", line 1515, in _query
14:20:20 ERROR nas.data.sync self._mongo_query = self._query_obj.to_query(self._document)
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/visitor.py", line 90, in to_query
14:20:20 ERROR nas.data.sync query = query.accept(QueryCompilerVisitor(document))
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/visitor.py", line 155, in accept
14:20:20 ERROR nas.data.sync return visitor.visit_query(self)
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/visitor.py", line 78, in visit_query
14:20:20 ERROR nas.data.sync return transform.query(self.document, **query.query)
14:20:20 ERROR nas.data.sync File "E:/alpha_maya_pyside/auxiliary/__all/MongoEngine-0.10.6/mongoengine/queryset/transform.py", line 61, in query
14:20:20 ERROR nas.data.sync raise InvalidQueryError(e)
14:20:20 ERROR nas.data.sync InvalidQueryError: 'DictField' object has no attribute 'document_type'
14:20:20 ERROR nas.data.sync sync failed
让类继承自Document而不是DynamicDocument确实解决了这个问题。我一直在深入研究MongoEngine的源代码,但没有真正跳出来对我。我唯一的猜测是,MongoEngine可能无法将DynamicField转换为DictField。
我增加了一个print语句MongoEngine-0.10.6/mongoengine /查询集/ transform.py:
try:
fields = _doc_cls._lookup_field(parts)
print fields
except Exception, e:
raise InvalidQueryError(e)
我只是在错误消息之前得到这个输出:
[<mongoengine.fields.DynamicField object at 0x00000000048B48D0>]
我走进mongoengine/base/document.py并检出__lookup_field函数。在那个函数内部是一个相当长的if/else语句。这是一段摘录。
if field is None:
# Look up first field from the document
if field_name == 'pk':
# Deal with "primary key" alias
field_name = cls._meta['id_field']
if field_name in cls._fields:
field = cls._fields[field_name]
elif cls._dynamic:
field = DynamicField(db_field=field_name)
elif cls._meta.get("allow_inheritance", False) or cls._meta.get("abstract", False):
# 744: in case the field is defined in a subclass
for subcls in cls.__subclasses__():
try:
field = subcls._lookup_field([field_name])[0]
except LookUpError:
continue
if field is not None:
break
else:
raise LookUpError('Cannot resolve field "%s"' % field_name)
else:
raise LookUpError('Cannot resolve field "%s"'
% field_name)
else:
ReferenceField = _import_class('ReferenceField')
GenericReferenceField = _import_class('GenericReferenceField')
if isinstance(field, (ReferenceField, GenericReferenceField)):
raise LookUpError('Cannot perform join in mongoDB: %s' %
'__'.join(parts))
if hasattr(getattr(field, 'field', None), 'lookup_member'):
new_field = field.field.lookup_member(field_name)
elif cls._dynamic and (isinstance(field, DynamicField) or
getattr(getattr(field, 'document_type'), '_dynamic')):
new_field = DynamicField(db_field=field_name)
如果你运行一个查询和使用,也就是说,一个StringField,则变量field
仍然None
。但是,如果使用DictField运行查询,则field
会被设置为<mongoengine.fields.DictField object at 0x0000000004506CF8>
之类的内容。我不知道如何field
设置为该值。无论如何,如果您正在查询的类恰好是DynamicDocument,那么您将被发送到循环的这一部分。
elif cls._dynamic and (isinstance(field, DynamicField) or
getattr(getattr(field, 'document_type'), '_dynamic')):
new_field = DynamicField(db_field=field_name)
我通过排除过程得出了这个结论。基本上,我找出了我不去的地方。正如你所看到的,由于DictField不是一个DynamicField,它将被查询为document_type
属性。 DictField没有导致InvalidQueryError的那个属性。
看起来现在的解决方案是不使用DictFields和DynamicDocuments,或者看看是否可以使用EmbeddedDocumentField,EmbeddedDocumentListField或ReferenceField与DynamicDocument。也许这是开发者的意图?
有趣。如果您查看mongoengine/fields.py,您将看到以下字段具有document_type属性:EmbeddedDocumentField,EmbeddedDocumentListField,CachedReferenceField。 –
函数_lookup_field实际上是BaseDocument(mongoengine/base/document.py)的一部分。它将您的模式(这是一个类)以及您用来执行查询的任何属性,并返回包含该字段及其父项的列表(根据注释)。我认为在这个功能中有些东西正在崩溃。 –