如何在 Flask Eve 中插入包含字典和列表的记录?
How can I insert records which have dicts and lists in Flask Eve?
我正在使用 Flask-Eve 为我的数据提供 API。我想使用 Eve 插入我的记录,以便我获得一个 _created 属性和其他 Eve 添加的属性。
我的两个字段是字典,一个是列表。当我尝试将其插入 Eve 时,结构似乎变平了,丢失了一些信息。试图告诉 Eve 有关字典和列表元素的信息时,我在 POST 上出错,说这些字段需要是字典和列表,但它们已经是了!有人可以帮助我并告诉我我做错了什么吗?
我的 Eve conf 是这样的:
'myendpoint': { 'allow_unknown': True,
'schema': { 'JobTitle': { 'type': 'string',
'required': True,
'empty': False,
'minlength': 3,
'maxlength': 99 },
'JobDescription': { 'type': 'string',
'required': True,
'empty': False,
'minlength': 32,
'maxlength': 102400 },
},
},
但是当我POST以下结构使用请求时:
{
"_id" : ObjectId("56e840686dbf9a5fe069220e"),
"Salary" : {
"OtherPay" : "On Application"
},
"ContactPhone" : "xx",
"JobTypeCodeList" : [
"Public Sector",
"Other"
],
"CompanyName" : "Scc",
"url" : "xx",
"JobTitle" : "xxx",
"WebAdID" : "TA7494725_1_1",
"JobDescription" : "xxxx",
"JobLocation" : {
"DisplayCity" : "BRIDGWATER",
"City" : "BRIDGWATER",
"StateProvince" : "Somerset",
"Country" : "UK",
"PostalCode" : "TA6"
},
"CustomField1" : "Permanent",
"CustomField3" : "FTJOBUKNCSG",
"WebAdManagerEmail" : "xxxx",
"JobType" : "Full",
"ProductID" : "JCPRI0UK"
}
post 行如下所示:
resp = requests.post(url, data = job)
它得到 'flattened' 并丢失了字典和列表中的信息:
{
"_id" : ObjectId("56e83f5a6dbf9a6395ea559d"),
"Salary" : "OtherPay",
"_updated" : ISODate("2016-03-15T16:59:06Z"),
"ContactPhone" : "xx",
"JobTypeCodeList" : "Public Sector",
"CompanyName" : "Scc",
"url" : "xxx",
"JobTitle" : "xx",
"WebAdID" : "TA7494725_1_1",
"JobDescription" : "xxx",
"JobLocation" : "DisplayCity",
"CustomField1" : "Permanent",
"_created" : ISODate("2016-03-15T16:59:06Z"),
"CustomField3" : "FTJOBUKNCSG",
"_etag" : "55d8d394141652f5dc2892a900aa450403a63d10",
"JobType" : "Full",
"ProductID" : "JCPRI0UK"
}
我已经尝试更新我的架构,说有些是字典和列表:
'JobTypeCodeList': { 'type': 'list'},
'Salary': { 'type': 'dict'},
'JobLocation': { 'type': 'dict'},
但是当我 POST 在新记录中时,我收到一条错误消息
{u'Salary': u'must be of dict type', u'JobTypeCodeList': u'must be of list type', u'JobLocation': u'must be of dict type'},
我已经在 POST 之前验证过 type(job.Salary) == dict
等等,所以我不确定如何解决这个问题。虽然我可以 POST 记录直接进入 MongoDB 好的,绕过 Eve,如果可能的话我更愿意使用 Eve。
如果这对其他人有用,我最终通过将平面结构发布到 Eve 中来解决这个问题,然后使用 on_insert 和 on_update 事件循环访问键并从中构建对象(和列表)。
它有点复杂,但它确实起到了作用,现在它就位了,使用起来相当透明。我通过 Eve 添加到 MongoDB 的对象现在具有嵌入式列表和散列,但它们也获得了方便的 Eve 属性,如 _created 和 _updated,而 POST 和 PATCH 请求也通过 Eve 的正常模式得到验证。
唯一真正尴尬的是on_insert和on_update发送的参数略有不同,所以下面的代码中有很多重复,我还没有重构。
任何字符都可以用作标志:我使用两个下划线来指示 key/values 应该作为单个对象结束,两个 & 符号表示应该拆分成一个列表的值。我现在发布的结构如下所示:
"Salary__OtherPay" : "On Application"
"ContactPhone" : "xx",
"JobTypeCodeList" : "Public Sector&&Other",
"CompanyName" : "Scc",
"url" : "xx",
"JobTitle" : "xxx",
"WebAdID" : "TA7494725_1_1",
"JobDescription" : "xxxx",
"JobLocation__DisplayCity" : "BRIDGWATER",
"JobLocation__City" : "BRIDGWATER",
"JobLocation__StateProvince" : "Somerset",
"JobLocation__Country" : "UK",
"JobLocation__PostalCode" : "TA6"
"CustomField1" : "Permanent",
"CustomField3" : "FTJOBUKNCSG",
"WebAdManagerEmail" : "xxxx",
"JobType" : "Full",
"ProductID" : "JCPRI0UK"
并且我的 Eve 架构已相应更新以验证这些新键名的值。然后在后端我定义了下面的函数,它检查传入的 keys/values 并将它们转换为 objects/lists,同时删除原始的 __ 和 && 数据:
import re
def flat_to_complex(items=None, orig=None):
if type(items) is dict: # inserts of new objects
if True: # just to force indentation
objects = {} # hash-based container for each object
lists = {} # hash-based container for each list
for key,value in items.items():
has_object_wildcard = re.search(r'^([^_]+)__', key, re.IGNORECASE)
if bool(has_object_wildcard):
objects[has_object_wildcard.group(1)] = None
elif bool(re.search(r'&&', unicode(value))):
lists[key] = str(value).split('&&')
for list_name, this_list in lists.items():
items[list_name] = this_list
for obj_name in objects:
this_obj = {}
for key,value in items.items():
if key.startswith('{s}__'.format(s=obj_name)):
match = re.search(r'__(.+)$', key)
this_obj[match.group(1)] = value
del(items[key])
objects[obj_name] = this_obj
for obj_name, this_obj in objects.items():
items[obj_name] = this_obj
elif type(items) is list: # updates to existing objects
for idx in range(len(items)):
if type(items[idx]) is dict:
objects = {} # hash-based container for each object
lists = {} # hash-based container for each list
for key,value in items[idx].items():
has_object_wildcard = re.search(r'^([^_]+)__', key, re.IGNORECASE)
if bool(has_object_wildcard):
objects[has_object_wildcard.group(1)] = None
elif bool(re.search(r'&&', unicode(value))):
lists[key] = str(value).split('&&')
for list_name, this_list in lists.items():
items[idx][list_name] = this_list
for obj_name in objects:
this_obj = {}
for key,value in items[idx].items():
if key.startswith('{s}__'.format(s=obj_name)):
match = re.search(r'__(.+)$', key)
this_obj[match.group(1)] = value
del(items[idx][key])
objects[obj_name] = this_obj
for obj_name, this_obj in objects.items():
items[idx][obj_name] = this_obj
然后我只告诉 Eve 运行 该函数用于插入和更新该集合:
app.on_insert_myendpoint += flat_to_complex
app.on_update_myendpoint += flat_to_complex
这实现了我所需要的,Mongo 中的结果记录与上述问题中的记录相同(具有 _created 和 _updated 属性)。它显然不理想,但它确实存在,而且一旦到位就很容易使用。
我正在使用 Flask-Eve 为我的数据提供 API。我想使用 Eve 插入我的记录,以便我获得一个 _created 属性和其他 Eve 添加的属性。
我的两个字段是字典,一个是列表。当我尝试将其插入 Eve 时,结构似乎变平了,丢失了一些信息。试图告诉 Eve 有关字典和列表元素的信息时,我在 POST 上出错,说这些字段需要是字典和列表,但它们已经是了!有人可以帮助我并告诉我我做错了什么吗?
我的 Eve conf 是这样的:
'myendpoint': { 'allow_unknown': True,
'schema': { 'JobTitle': { 'type': 'string',
'required': True,
'empty': False,
'minlength': 3,
'maxlength': 99 },
'JobDescription': { 'type': 'string',
'required': True,
'empty': False,
'minlength': 32,
'maxlength': 102400 },
},
},
但是当我POST以下结构使用请求时:
{
"_id" : ObjectId("56e840686dbf9a5fe069220e"),
"Salary" : {
"OtherPay" : "On Application"
},
"ContactPhone" : "xx",
"JobTypeCodeList" : [
"Public Sector",
"Other"
],
"CompanyName" : "Scc",
"url" : "xx",
"JobTitle" : "xxx",
"WebAdID" : "TA7494725_1_1",
"JobDescription" : "xxxx",
"JobLocation" : {
"DisplayCity" : "BRIDGWATER",
"City" : "BRIDGWATER",
"StateProvince" : "Somerset",
"Country" : "UK",
"PostalCode" : "TA6"
},
"CustomField1" : "Permanent",
"CustomField3" : "FTJOBUKNCSG",
"WebAdManagerEmail" : "xxxx",
"JobType" : "Full",
"ProductID" : "JCPRI0UK"
}
post 行如下所示:
resp = requests.post(url, data = job)
它得到 'flattened' 并丢失了字典和列表中的信息:
{
"_id" : ObjectId("56e83f5a6dbf9a6395ea559d"),
"Salary" : "OtherPay",
"_updated" : ISODate("2016-03-15T16:59:06Z"),
"ContactPhone" : "xx",
"JobTypeCodeList" : "Public Sector",
"CompanyName" : "Scc",
"url" : "xxx",
"JobTitle" : "xx",
"WebAdID" : "TA7494725_1_1",
"JobDescription" : "xxx",
"JobLocation" : "DisplayCity",
"CustomField1" : "Permanent",
"_created" : ISODate("2016-03-15T16:59:06Z"),
"CustomField3" : "FTJOBUKNCSG",
"_etag" : "55d8d394141652f5dc2892a900aa450403a63d10",
"JobType" : "Full",
"ProductID" : "JCPRI0UK"
}
我已经尝试更新我的架构,说有些是字典和列表:
'JobTypeCodeList': { 'type': 'list'},
'Salary': { 'type': 'dict'},
'JobLocation': { 'type': 'dict'},
但是当我 POST 在新记录中时,我收到一条错误消息
{u'Salary': u'must be of dict type', u'JobTypeCodeList': u'must be of list type', u'JobLocation': u'must be of dict type'},
我已经在 POST 之前验证过 type(job.Salary) == dict
等等,所以我不确定如何解决这个问题。虽然我可以 POST 记录直接进入 MongoDB 好的,绕过 Eve,如果可能的话我更愿意使用 Eve。
如果这对其他人有用,我最终通过将平面结构发布到 Eve 中来解决这个问题,然后使用 on_insert 和 on_update 事件循环访问键并从中构建对象(和列表)。
它有点复杂,但它确实起到了作用,现在它就位了,使用起来相当透明。我通过 Eve 添加到 MongoDB 的对象现在具有嵌入式列表和散列,但它们也获得了方便的 Eve 属性,如 _created 和 _updated,而 POST 和 PATCH 请求也通过 Eve 的正常模式得到验证。
唯一真正尴尬的是on_insert和on_update发送的参数略有不同,所以下面的代码中有很多重复,我还没有重构。
任何字符都可以用作标志:我使用两个下划线来指示 key/values 应该作为单个对象结束,两个 & 符号表示应该拆分成一个列表的值。我现在发布的结构如下所示:
"Salary__OtherPay" : "On Application"
"ContactPhone" : "xx",
"JobTypeCodeList" : "Public Sector&&Other",
"CompanyName" : "Scc",
"url" : "xx",
"JobTitle" : "xxx",
"WebAdID" : "TA7494725_1_1",
"JobDescription" : "xxxx",
"JobLocation__DisplayCity" : "BRIDGWATER",
"JobLocation__City" : "BRIDGWATER",
"JobLocation__StateProvince" : "Somerset",
"JobLocation__Country" : "UK",
"JobLocation__PostalCode" : "TA6"
"CustomField1" : "Permanent",
"CustomField3" : "FTJOBUKNCSG",
"WebAdManagerEmail" : "xxxx",
"JobType" : "Full",
"ProductID" : "JCPRI0UK"
并且我的 Eve 架构已相应更新以验证这些新键名的值。然后在后端我定义了下面的函数,它检查传入的 keys/values 并将它们转换为 objects/lists,同时删除原始的 __ 和 && 数据:
import re
def flat_to_complex(items=None, orig=None):
if type(items) is dict: # inserts of new objects
if True: # just to force indentation
objects = {} # hash-based container for each object
lists = {} # hash-based container for each list
for key,value in items.items():
has_object_wildcard = re.search(r'^([^_]+)__', key, re.IGNORECASE)
if bool(has_object_wildcard):
objects[has_object_wildcard.group(1)] = None
elif bool(re.search(r'&&', unicode(value))):
lists[key] = str(value).split('&&')
for list_name, this_list in lists.items():
items[list_name] = this_list
for obj_name in objects:
this_obj = {}
for key,value in items.items():
if key.startswith('{s}__'.format(s=obj_name)):
match = re.search(r'__(.+)$', key)
this_obj[match.group(1)] = value
del(items[key])
objects[obj_name] = this_obj
for obj_name, this_obj in objects.items():
items[obj_name] = this_obj
elif type(items) is list: # updates to existing objects
for idx in range(len(items)):
if type(items[idx]) is dict:
objects = {} # hash-based container for each object
lists = {} # hash-based container for each list
for key,value in items[idx].items():
has_object_wildcard = re.search(r'^([^_]+)__', key, re.IGNORECASE)
if bool(has_object_wildcard):
objects[has_object_wildcard.group(1)] = None
elif bool(re.search(r'&&', unicode(value))):
lists[key] = str(value).split('&&')
for list_name, this_list in lists.items():
items[idx][list_name] = this_list
for obj_name in objects:
this_obj = {}
for key,value in items[idx].items():
if key.startswith('{s}__'.format(s=obj_name)):
match = re.search(r'__(.+)$', key)
this_obj[match.group(1)] = value
del(items[idx][key])
objects[obj_name] = this_obj
for obj_name, this_obj in objects.items():
items[idx][obj_name] = this_obj
然后我只告诉 Eve 运行 该函数用于插入和更新该集合:
app.on_insert_myendpoint += flat_to_complex
app.on_update_myendpoint += flat_to_complex
这实现了我所需要的,Mongo 中的结果记录与上述问题中的记录相同(具有 _created 和 _updated 属性)。它显然不理想,但它确实存在,而且一旦到位就很容易使用。