J'utilise Flask et MongoDB. J'essaie de convertir le contenu de request.form en quelque chose de approprié pour enregistrer via PyMongo. Cela semble être quelque chose qui devrait arriver assez souvent pour avoir une solution toute faite.
Donc, ce que Flask me donne est quelque chose comme:
ImmutableMultiDict([('default', u''), ('required': u'on'), ('name', u'short_text'), ('name', u'another'), ('submit', u'Submit')])
Et ce que je cherche à obtenir est quelque chose de proche:
{
'default': '',
'name': ['short_text', 'another'],
'required': true
}
>>> 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)
est la chose à garder à l'esprit. Voir la documentation pertinente
La structure de données Flask ImmutableMultiDict
a une méthode to_dict
intégrée.
Cette connaissance, en plus de la propriété request
de Flask __, propriété form
étant une ImmutableMultiDict
, permet un traitement simple d'une demande de formulaire POST à MongoDB.
Voir ci-dessous pour un exemple naïf:
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)
Vous pouvez utiliser getlist de werkzeug pour écrire un code comme celui-ci
data = dict((key, request.form.getlist(key)) for key in request.form.keys())
Désormais, chaque clé de data
sera une liste contenant 1 élément supplémentaire. Pour obtenir des résultats exactement dans votre format, faites ceci
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())
Cela est maintenant inefficace car pour chaque touche, il y a 3 appels à request.form.getlist(key)
. Vous pouvez écrire une boucle et la contourner.
request.form.to_dict()
donnerait ce dont vous avez besoin
>>> 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'}
Comparaison des méthodes dict()
et .to_dict()
avant et après la version 3.6 de Python.
from werkzeug.datastructures import ImmutableMultiDict
imd = ImmutableMultiDict([('default', u''), ('required', u'on'), ('name', u'short_text'), ('name', u'another'), ('submit', u'Submit')])
Jusqu'à 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'}
Ainsi,
dict(imd) == imd.to_dict(flat=False)
#output: True
À partir de 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'}
Ainsi,
dict(imd) == imd.to_dict(flat=False)
#output: False
Utiliser .to_dict()
avec flat=True/False
est une option plus sûre.