【问题标题】:How can I insert records which have dicts and lists in Flask Eve?如何在 Flask Eve 中插入包含字典和列表的记录?
【发布时间】:2016-07-01 08:02:05
【问题描述】:

我正在使用 Flask-Eve 为我的数据提供 API。我想使用 Eve 插入我的记录,以便获得 _created 属性和其他 Eve 添加的属性。

我的两个字段是字典,一个是列表。当我尝试将其插入 Eve 时,结构似乎变得扁平,丢失了一些信息。试图告诉 Eve dict & list 元素在 POST 上给我一个错误,说这些字段需要是 dicts 和列表,但它们已经是!请有人可以帮助我并告诉我我做错了什么?

我的 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 },
                           },
               },

但是当我使用请求发布以下结构时:

{
        "_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"
}

帖子如下所示:

resp = requests.post(url, data = job)

它被“扁平化”并丢失了字典和列表中的信息:

{
        "_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'},

但是当我在新记录中发布时,我收到一条错误消息

 {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 等,所以我不确定如何解决这个问题。虽然我可以将记录直接发布到 MongoDB 中,但可以绕过 Eve,但如果可能的话,我更喜欢使用 Eve。

【问题讨论】:

    标签: python flask eve


    【解决方案1】:

    如果这对其他人有用,我最终通过将平面结构发布到 Eve 中解决了这个问题,然后使用 on_insert 和 on_update 事件循环遍历键并从中构造对象(和列表)。

    这有点令人费解,但它可以解决问题,现在它已经到位,使用起来相当透明。我通过 Eve 添加到 MongoDB 的对象现在具有嵌入的列表和哈希,但它们也获得了方便的 Eve 属性,如 _created 和 _updated,而 POST 和 PATCH 请求也通过 Eve 的正常模式得到验证。

    唯一真正尴尬的是 on_insert 和 on_update 发送的参数略有不同,所以下面的代码中有很多重复,我还没有重构出来。

    任何字符都可以用作标志:我使用两个下划线表示应该作为单个对象结束的键/值,并使用两个 & 符号表示应该拆分为列表的值。我现在发布的结构如下所示:

        "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 架构已相应更新,以验证这些新键名的值。然后在后端我定义了下面的函数,它检查传入的键/值并将它们转换为对象/列表,并删除原始的 __ 和 && 数据:

    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 属性)。这显然不是很理想,但它可以实现,而且一旦到位就很容易使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-25
      • 2020-01-19
      • 2016-05-16
      • 2018-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多