Reputation: 21
I am trying to create a data entry form "dynamically" (currently, I am using an array with 3 values, but in the future the number of elements in the array might vary) with nested dictionaries. This seems to work fine and the form is "properly" renders the html template (properly = I see what I would expect to see which is a form with 3 rows for each element in the array with 4 columns).
The problem is when I enter data in the form through the browser and click the "Save Data" button. At that point I want to get data entered in the form by the user and do something with it (do calculations, save it, etc.).
Getting request data seems like a fairly straightforward task when the form does not have nested fields (based on all examples I have seen), but in my case it is driving me nuts.
So far, the only way I get to see the data submitted by the user is with "request.form" but that is a MultiDict object and has no structure. The weird part to me is request.data returns an empty string and request.get_json() gives an error ("Failed to decode JSON")
The specific question is: If I want to get the form data in json or dictionary format (structure I defined), what am I doing wrong? What else should I include in my code. Otherwise, if this behavior is expected and all I can get is a MultiDict, what is the best way to then reconstruct the data to json object?
This is my view.py code: The GET method first create the form structure "dynamically" and render the report.htlm template. The POST method is supposed to check what form button was clicked by the user and, get the data entered by the user and do something with it. Note that for now I only have "print" statements to see what I was getting.
@app.route('/report', methods=['GET', 'POST'])
def report():
if request.method == 'POST':
if request.form['submit'] == 'Save Data':
print (request.form)
print(request.get_json(force=True)
print (request.data)
return redirect(url_for('report'))
elif request.form['submit'] == 'View Data':
return redirect(url_for('report'))
elif request.method == 'GET':
jsonForm = populate_Form()
form = ProductionReport.from_json(jsonForm)
return render_template('report.html',
title='Report',
form=form)
def populate_Form():
j = {"line_production": []}
lines = ["Standard","Sport","Luxury"]
for l in lines:
j["line_production"].append(
{"line": l, "sku": "", "qty": "", "price": ""})
return j
These are my forms:
from flask.ext.wtf import Form
from wtforms import StringField, BooleanField, IntegerField, FieldList, FormField, FloatField
from wtforms.validators import DataRequired
import wtforms_json
wtforms_json.init()
class LineProduction(Form):
line = StringField('line')
sku = IntegerField('sku', default = 0)
qty = IntegerField('qty', default = 0)
price = IntegerField('price', default = 0)
class ProductionReport(Form):
factory_id = StringField('Factory ID')
year = StringField('Year')
month = StringField('Month')
line_production = FieldList(FormField(LineProduction), label='line_production')
Upvotes: 1
Views: 3684
Reputation: 91
To avoid this error you can use this code:
body = request.get_json(silent=True)
if body is None:
return jsonify({'error' : 'Empty request body'})
The trick is add silent=True and now you can control the result
Upvotes: 0
Reputation: 23484
As it was mentioned here
request.data
Contains the incoming request data as string in case it came with a mimetype Flask does not handle.
That's why you get empty string in request.data
You can convert request.form
to dict, as you mentioned, it's MultiDict
object, but it can be simply be converted to dict
object with to_dict
method. And with dict
object you can do whatever you like.
Upvotes: 1