Wednesday, November 29, 2017

Flask Form data duplicates on submit

Leave a Comment

i am trying to populate a table of current values, then change it with intention of finding the diffs of original and after. i simplify my code in the following to replicate the issue: -

webapp.py

from flask import Flask, render_template from flask_wtf import FlaskForm from wtforms import StringField, DecimalField, fields import pandas as pd  app=Flask(__name__) app.config['SECRET_KEY'] = 'wtf'  class stockForm(FlaskForm):     stock=StringField()     price= DecimalField()      def __init__(self, csrf_enabled=False, *args, **kwargs):         super(stockForm, self).__init__(csrf_enabled=csrf_enabled, *args, **kwargs)  class stockListForm(FlaskForm):     stockItem=fields.FieldList(fields.FormField(stockForm))   @app.route('/sEntry', methods=['GET','POST']) def sEntry():     form=stockListForm()     stocklist=pd.DataFrame(data=[['abc',10.17],['bcd',11.53],['edf',12.19]],columns=['stock','price'])          for stock in stocklist.itertuples():         sForm=stockForm()         sForm.stock=stock.stock         sForm.price=stock.price         form.stockItem.append_entry(sForm)      if form.validate_on_submit():         results = []         for idx, data in enumerate(form.stockItem.data):             results.append(data)         print(results)         del form         return render_template('results.html', results=results)     print(form.errors)     return render_template('sEntry.html',form=form)   if __name__=='__main__':     app.run(debug=True, use_reloader=True, host='0.0.0.0', port=int('5050')) 

sEntry.html

<html lang="en">   <head>     <meta charset="utf-8">   </head> <body>      <form action="" method="POST" name="form">     {{ form.name}}     {{ form.hidden_tag() }}     <div>         <table>             <thead >             <tr class="col">                 <th style="width: 30px">stock</th>                 <th style="width: 50px">price</th>             </tr>             </thead>             {% for stock in form.stockItem %}             <tr class="col">                 <td>{{ stock.stock }}</td>                 <td>{{ stock.price }}</td>             </tr>             {% endfor %}         </table>     </div>     <p><input type="submit" name="edit" value="Send"></p>     </form> </body> </html> 

results.html

<ul> {% for line in results %}     <li>{{ line }}</li> {% endfor %}  </ul> 

if I am to change the values of a few of the field, the variable results generated will have duplicate of 6 rows of data from my original 3 rows in the dataframes e.g.

{'price': Decimal('10.17'), 'stock': 'abc'} {'price': Decimal('13'),    'stock': 'bcd'} {'price': Decimal('12.19'), 'stock': 'edf'} {'price': 10.17, 'stock': 'abc'} {'price': 11.529999999999999, 'stock': 'bcd'} {'price': 12.19, 'stock': 'edf'} 

Furthermore, i also have issues my original Decimals used in turning into some long float values, in above example, i change bcd value from 11.53 to 13, the original value become long float figure, the rest that i didnt edit stay as original.

I could have the dirty solution of cutting the results into half and compare values between both halves, rounding those long floats to find values that have change, but seems very inefficient.

can anyone assist?

1 Answers

Answers 1

Firstly, you need to use proper Decimal type in the Pandas DataFrame. (Which can be handled by Pandas by using Numpy's dtype with an object).

Secondly, you were filling the form with original data when POST request occurred.

Somewhat fixed view function would look like this:

@app.route('/', methods=['GET','POST']) def sEntry():     # Create form and fill it with request data     form = stockListForm(request.form)      # Set up initial data with proper Decimal objects     stocklist=pd.DataFrame(data=[['abc',Decimal('10.17')],['bcd',Decimal('11.53')],['edf',Decimal('12.19')]],columns=['stock','price'])          # Handle valid POST request     if form.validate_on_submit():         # Convert form data to dictionary (so we can later easily query stock price)         stocks = {i['stock']: i['price'] for i in form.stockItem.data}          # Generate result (as generator) ...         results = ((i.stock, i.price, i.price - stocks[i.stock]) for i in stocklist.itertuples())          # ... and push it to template         return render_template('results.html', results=results)      print(form.errors)      # ...build initial form for GET request      for stock in stocklist.itertuples():         sForm=stockForm()         sForm.stock=stock.stock         sForm.price=stock.price         form.stockItem.append_entry(sForm)      return render_template('sEntry.html',form=form) 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment