git*_*rik 11 python mongodb mongoengine
是否可以使用python dict更新MongoEngine文档?
例如:
class Pets(EmbeddedDocument):
name = StringField()
class Person(Document):
name = StringField()
address = StringField()
pets = ListField(EmbeddedDocumentField(Pets))
p = Person()
p.update_with_dict({
"name": "Hank",
"address": "Far away",
"pets": [
{
"name": "Scooter"
}
]
})
Run Code Online (Sandbox Code Playgroud)
好的,我刚刚为它做了一个功能.
你称之为update_document(document, data_dict).它将循环遍历项目data_dict并使用密钥获取字段实例data_dict.然后,它会调用field_value(field, value)这里field是该领域的实例.field_value()将检查字段的类型,field.__class__并根据该返回值查看MongoEngine期望的值.例如,StringField可以按原样返回法线的值,但是对于a EmbeddedDocumentField,需要创建该嵌入文档类型的实例.它也为列表字段中的项目执行此操作.
from mongoengine import fields
def update_document(document, data_dict):
def field_value(field, value):
if field.__class__ in (fields.ListField, fields.SortedListField):
return [
field_value(field.field, item)
for item in value
]
if field.__class__ in (
fields.EmbeddedDocumentField,
fields.GenericEmbeddedDocumentField,
fields.ReferenceField,
fields.GenericReferenceField
):
return field.document_type(**value)
else:
return value
[setattr(
document, key,
field_value(document._fields[key], value)
) for key, value in data_dict.items()]
return document
Run Code Online (Sandbox Code Playgroud)
用法:
class Pets(EmbeddedDocument):
name = StringField()
class Person(Document):
name = StringField()
address = StringField()
pets = ListField(EmbeddedDocumentField(Pets))
person = Person()
data = {
"name": "Hank",
"address": "Far away",
"pets": [
{
"name": "Scooter"
}
]
}
update_document(person, data)
Run Code Online (Sandbox Code Playgroud)
在这里玩游戏很晚,但是FWIW,MongoEngine为此提供了内置解决方案。
不管你想create还是update可以做到以下几点:
class Pets(EmbeddedDocument):
name = StringField()
class Person(Document):
name = StringField()
address = StringField()
pets = ListField(EmbeddedDocumentField(Pets))
p = Person(**{
"name": "Hank",
"address": "Far away",
"pets": [{"name": "Scooter"}]
})
p.save()
Run Code Online (Sandbox Code Playgroud)
唯一的区别update是您需要坚持使用id。这样,mongoengine不会复制现有文档id并更新它。
试试更多这样的东西
p.update(**{
"set__name": "Hank",
"set__address": "Far away"
})
Run Code Online (Sandbox Code Playgroud)
我已经尝试了上面的大部分答案,但似乎没有一个真正适用于嵌入式文档。即使他们更新了字段,他们也删除了嵌入式文档中未填写字段的内容。
为此,我决定采用@hckjck 建议的路径,我编写了一个简单的函数,将 dict 转换为格式,以便可以通过以下方式处理document.update:
def convert_dict_to_update(dictionary, roots=None, return_dict=None):
"""
:param dictionary: dictionary with update parameters
:param roots: roots of nested documents - used for recursion
:param return_dict: used for recursion
:return: new dict
"""
if return_dict is None:
return_dict = {}
if roots is None:
roots = []
for key, value in dictionary.iteritems():
if isinstance(value, dict):
roots.append(key)
convert_dict_to_update(value, roots=roots, return_dict=return_dict)
roots.remove(key) # go one level down in the recursion
else:
if roots:
set_key_name = 'set__{roots}__{key}'.format(
roots='__'.join(roots), key=key)
else:
set_key_name = 'set__{key}'.format(key=key)
return_dict[set_key_name] = value
return return_dict
Run Code Online (Sandbox Code Playgroud)
现在这个数据:
{u'communication': {u'mobile_phone': u'2323232323', 'email':{'primary' : 'email@example.com'}}}
Run Code Online (Sandbox Code Playgroud)
将转换为:
{'set__communication__mobile_phone': u'2323232323', 'set__communication__email__primary': 'email@example.com'}
Run Code Online (Sandbox Code Playgroud)
哪个可以这样使用
document.update(**conv_dict_to_update(data))
Run Code Online (Sandbox Code Playgroud)
也可在此要点中找到:https : //gist.github.com/Visgean/e536e466207bf439983a
我不知道这有多有效,但它确实有效。
| 归档时间: |
|
| 查看次数: |
7925 次 |
| 最近记录: |