Flask request.form contains data but request.data is empty and request.get_json() returns error
<p>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).</p>

<p>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.).</p>

<p>Getting request data seems like a fairly straightforward task when the form does <strong>not</strong> have nested fields (based on all examples I have seen), but in my case it is driving me nuts.</p>

<p>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")</p>

<p><strong>The specific question is:</strong> 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?</p>

<p>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. </p>

<pre><code>@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
</code></pre>

<p>These are my forms:</p>

<pre><code>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')
</code></pre>

<p>As it was mentioned <a href="http://stackoverflow.com/a/16664376/3124746">here</a></p>

<blockquote>
  <p><code>request.data</code> Contains the incoming request data as string in case it came with a mimetype Flask does not handle.</p>
</blockquote>

<p>That's why you get empty string in <code>request.data</code></p>

<p>You can convert <code>request.form</code> to dict, as you mentioned, it's <code>MultiDict</code> object, but it can be simply be converted to <code>dict</code> object with <a href="http://werkzeug.pocoo.org/docs/0.11/datastructures/#werkzeug.datastructures.MultiDict.to_dict" rel="nofollow"><code>to_dict</code></a> method. And with <code>dict</code> object you can do whatever you like.</p>

python flask wtforms wtforms-json