I am using Flask and MongoDB. I am trying to convert the content of request.form into something suitable for saving via PyMongo. It seems like something that should come up
You can use werkzeug's getlist to write code like this
data = dict((key, request.form.getlist(key)) for key in request.form.keys())
Now each key of data
would be a list which would contain 1 more element. To get results exactly in your format do this
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())
Now this is inefficient because for each key there are 3 calls to request.form.getlist(key)
. You can write a loop and get around it.
The Flask ImmutableMultiDict
data structure has a built in to_dict
method.
This knowledge in addition to the Flask request
object form
property being an ImmutableMultiDict
allows for simple handling of a form POST request to MongoDB.
See below for a naive example:
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)
Comparison of dict()
and .to_dict()
method before and after python version 3.6.
from werkzeug.datastructures import ImmutableMultiDict
imd = ImmutableMultiDict([('default', u''), ('required', u'on'), ('name', u'short_text'), ('name', u'another'), ('submit', u'Submit')])
Till 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'}
Thus,
dict(imd) == imd.to_dict(flat=False)
#output: True
From python3.6 onwards
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'}
Thus,
dict(imd) == imd.to_dict(flat=False)
#output: False
Using .to_dict()
with flat=True/False
is a safer option.
>>> 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)
is the thing to keep in mind. See the relevant documentation
request.form.to_dict()
would yield what you need
>>> 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'}