在 Flask 中将表单 POST 对象转换为适合 mongodb 的表示形式

Posted

技术标签:

【中文标题】在 Flask 中将表单 POST 对象转换为适合 mongodb 的表示形式【英文标题】:In Flask convert form POST object into a representation suitable for mongodb 【发布时间】:2012-11-11 09:48:27 【问题描述】:

我正在使用 Flask 和 MongoDB。我正在尝试将 request.form 的内容转换为适合通过 PyMongo 保存的内容。这似乎应该经常出现以提供现成的解决方案。

所以 Flask 给我的是这样的:

ImmutableMultiDict([('default', u''), ('required': u'on'), ('name', u'short_text'), ('name', u'another'), ('submit', u'Submit')])

而我想要得到的是接近这个的东西:


  'default': '',
  'name': ['short_text', 'another'],
  'required': true

【问题讨论】:

为什么需要它?您可以像在字典中访问一样访问这些值,而无需对其进行转换。 like d['required'] 给你真实的回报。 @Abdul,如果你想循环通过 ImmutableNutiDict(),那么你可以像通常的字典一样做,但是如果你想将它作为一个整体用作一个字典,例如,使用合并字典z=**x,**y,那么它不起作用,该值周围会有方块,例如 ...,'name':['short_text'],。 【参考方案1】:
>>> from werkzeug.datastructures import ImmutableMultiDict
>>> imd = ImmutableMultiDict([('default', u''), ('required', u'on'), ('name', u'short_text'), ('name', u'another'), ('submit', u'Submit')])
>>> imd.to_dict(flat=False)
>>> 'default': [''], 
'name': ['short_text', 'another'],
'required': ['on'],
'submit': ['Submit']

.to_dict(flat=False) 是要记住的事情。见相关documentation

【讨论】:

只需使用.to_dict() 方法,如imd.to_dict()。这样每个值都不是一个列表,就像在您的解决方案中一样。你也不需要导入 ImmutableMultiDict 我可能会更新这个答案以包括评论建议做的事情。 .to_dict() 的使用将是在此处将这些值作为列表删除的方法。我会保持你的答案不变,但添加它并展示使用 to_dict() 的区别。 imd.to_dict() 不合适,因为它会丢失重复的条目 imd.to_dict(flat=False) 正是 OP 正在寻找的。请参阅上面的编辑答案。 使用imd.to_dict(flat=True) 获取键/值对【参考方案2】:

Flask ImmutableMultiDict 数据结构有一个内置的to_dict 方法。

除了 Flask request 对象 form 属性是 ImmutableMultiDict 之外,这些知识还允许简单处理对 MongoDB 的表单 POST 请求。

下面是一个简单的例子:

from flask import request

@app.route('/api/v1/account', methods=['POST'])
def create_account():
    """Create user account"""
    account_dict = request.form.to_dict()

    db.account.insert_one(account_dict)

【讨论】:

【参考方案3】:

你可以使用 werkzeug 的getlist 来写这样的代码

data = dict((key, request.form.getlist(key)) for key in request.form.keys())

现在data 的每个键都将是一个包含1 个以上元素的列表。要获得完全符合您格式的结果,请执行此操作

data = dict((key, request.form.getlist(key) if len(request.form.getlist(key)) > 1 else request.form.getlist(key)[0]) for key in request.form.keys())

现在这是低效的,因为每个键都有 3 次调用 request.form.getlist(key)。您可以编写一个循环并绕过它。

【讨论】:

【参考方案4】:

request.form.to_dict() 会产生你需要的东西

【讨论】:

【参考方案5】:

python 3.6版本前后dict().to_dict()方法对比。

from werkzeug.datastructures import ImmutableMultiDict
imd = ImmutableMultiDict([('default', u''), ('required', u'on'), ('name', u'short_text'), ('name', u'another'), ('submit', u'Submit')])

到python3.5

dict(imd)
#output: 'default': [''], 'required': ['on'], 'name': ['short_text', 'another'], 'submit': ['Submit']

imd.to_dict(flat=false)
#output: 'default': [''], 'required': ['on'], 'name': ['short_text', 'another'], 'submit': ['Submit']

imd.to_dict(flat=True) # or imd.to_dict() 
#output: 'default': '', 'required': 'on', 'name': 'short_text', 'submit': 'Submit'

因此,

dict(imd) == imd.to_dict(flat=False)
#output: True

从python3.6开始

dict(imd)
#output: 'default': '', 'required': 'on', 'name': 'short_text', 'submit': 'Submit'

imd.to_dict(flat=false)
#output: 'default': [''], 'required': ['on'], 'name': ['short_text', 'another'], 'submit': ['Submit']

imd.to_dict(flat=True) # or imd.to_dict() 
#output: 'default': '', 'required': 'on', 'name': 'short_text', 'submit': 'Submit'

因此,

dict(imd) == imd.to_dict(flat=False)
#output: False

.to_dict()flat=True/False 一起使用是更安全的选择。

【讨论】:

这太有帮助了。我复活了一个 2 年前的项目,一堆测试被打破了,我想知道这个网站到底是怎么运行的……原来正在运行的网站正在使用 dict() 和 3.5。切换到 3.6 和 flat=False 在 Python 3.7 windows 10 上运行 dict(ImmutableMultiDict) 对我来说效果很好。当我在 Python 3.7 dict(ImmutableMultiDict) 上将项目部署到 Windows Server 2016 时,将 dict 值作为列表返回。我不得不使用.to_dict()【参考方案6】:
>>> from werkzeug.datastructures import ImmutableMultiDict
>>> so = ImmutableMultiDict([('default', u''), ('required', u'on'), ('name', u'short_text'), ('name', u'another'), ('submit', u'Submit')])

# Most earlier answers have comments suggesting so.to_dict()
# It doesn't work, duplicates are lost like in a normal dict
>>> so.to_dict()
'default': '', 'required': 'on', 'name': 'short_text', 'submit': 'Submit'

# The response by Vb407 is better but litters lists everywhere
>>> dso = dict(so)
'default': [''], 'required': ['on'], 'name': ['short_text', 'another'], 'submit': ['Submit']

# We can achieve the requested state by cleaning this up
>>>  k: dso[k][0] if len(dso[k]) <= 1 else dso[k] for k in dso 
'default': '', 'required': 'on', 'name': ['short_text', 'another'], 'submit': 'Submit'

【讨论】:

这是最佳答案。尤其是最后一种区分列表和字符串的方法是完美的。

以上是关于在 Flask 中将表单 POST 对象转换为适合 mongodb 的表示形式的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Javascript 中将表单数组转换为 JSON? (对象数组)?

在 Django REST Framework 中将 GET 参数转换为 Request 对象上的 POST 数据

Flask表单疑问,这个name是怎么传进来的

如何在 Go 中将 JSON 对象数组转换为具有默认值的结构数组?

如何在reactjs中将数据二进制转换为图像?

如何在 symfony2 中将 json 转换为 php 对象?