0

I am creating a Dataframe by taking input file from user on a website and processing it.After that I want the user to download the final result in a csv file.For that a Dataframe is required from previous function.

I have tried passing the dataframe but it is giving me error as it is defined in another function.

My code is

from flask import Flask, render_template, request, redirect
from werkzeug import secure_filename
app = Flask(__name__)


@app.route('/uploader', methods = ['GET','POST'])
def upload():
 new=nrecs[['UserID','ProductID','Rating']]
 new['Recommendations'] = list(zip(new.ProductID, new.Rating))
 res=new[['UserID','Recommendations']]  
 res_new=res['Recommendations'].groupby([res.UserID]).apply(list).reset_index()
 pd.options.display.max_colwidth = 500
 return render_template('simple.html', tables=[res_new.to_html(classes='data')], titles='') 

@app.route('/download-csv', methods = ['GET'])
def download():
return res_new.to_csv('Recommendations.csv')

This is a small snipet of my code not the full code.

When a user will click on download recommendations button it should download the csv file.

Is there any other way around it can be done.

Neha patel
  • 143
  • 2
  • 12
  • I don't see where/how `nrecs` is defined. Does it come from a form submission in that /uploader route? – tandy Mar 17 '19 at 07:23
  • This is not the full code I have tried to upload the important parts of my code as it would be lenghty..nrecs is coming from after processing the file which user have uploaded.I have not shown that code. – Neha patel Mar 17 '19 at 07:28
  • I want to use res_new dataframe in another function download () which is defined below in the code. – Neha patel Mar 17 '19 at 07:29

2 Answers2

2

You can also store the file on the server and send it to the user in your download-csv route. Here is a send file tutorial

from flask import Flask, render_template, send_file
app = Flask(__name__)

@app.route('/uploader', methods = ['GET','POST'])
def upload():
    new=nrecs[['UserID','ProductID','Rating']]
    new['Recommendations'] = list(zip(new.ProductID, new.Rating))
    res=new[['UserID','Recommendations']]
    res_new=res['Recommendations'].groupby([res.UserID]).apply(list).reset_index()

    # store the dataframe on the server.
    res_new.to_csv('Recommendations.csv')

    pd.options.display.max_colwidth = 500
    return render_template('simple.html', tables=[res_new.to_html(classes='data')], titles='')

@app.route('/download-csv', methods = ['GET'])
def download():

    # return the CSV file to the user here.
    return send_file('Recommendations.csv')
tandy
  • 1,931
  • 4
  • 24
  • 28
  • 1
    Thank you for your answer.It did help me with little changes in my code.I have saved the filename in a global variable and converted the file with the same name in csv format.Then it can be downloaded through send_file() path. – Neha patel Apr 06 '19 at 10:46
0

You can try using a session object. See this question/answer. However, depending on the size of the dataframe, and what you are ultimately trying to do, this may not be the best way to do this. If you are trying to set up upload/download routes, storing the file on the server/elsewhere and then sending it to the user when they request it may be a better solution.

from flask import Flask, render_template, session
app = Flask(__name__)
# secret key is needed for session
app.secret_key = 'your secret key'

@app.route('/uploader', methods = ['GET','POST'])
def upload():
    new=nrecs[['UserID','ProductID','Rating']]
    new['Recommendations'] = list(zip(new.ProductID, new.Rating))
    res=new[['UserID','Recommendations']]
    res_new=res['Recommendations'].groupby([res.UserID]).apply(list).reset_index()

    session['reco_df'] = res_new

    pd.options.display.max_colwidth = 500
    return render_template('simple.html', tables=[res_new.to_html(classes='data')], titles='')

@app.route('/download-csv', methods = ['GET'])
def download():
    return session['reco_df'].to_csv('Recommendations.csv')
tandy
  • 1,931
  • 4
  • 24
  • 28
  • What is not working? What errors are you getting, etc? – tandy Mar 17 '19 at 07:59
  • I am getting KeyError: reco_df – Neha patel Mar 17 '19 at 16:22
  • Is that happening when you try to download, or in which route? Have you tried to print out what is in the session variable? – tandy Mar 17 '19 at 21:14
  • The key error is solved.After searching I came to know that for storing dataframe in session I have to use method given in this answer. https://stackoverflow.com/questions/43302961/trying-load-a-pandas-dataframe-into-flask-session-and-use-that-throughout-the-se – Neha patel Mar 18 '19 at 15:51
  • But now I am getting error as UserWarning: The "b'session'" cookie is too large: the value was 25048 bytes but the header required 26 extra bytes. The final size was 25074 bytes but the limit is 4093 bytes. Browsers may silently ignore cookies larger than this. – Neha patel Mar 18 '19 at 15:52
  • @Nehapatel -- so you are going to have to store/cache the dataframe somewhere and then only retrieve it when someone goes to /download it. For example, you can save the DF on the server as a CSV and then just download it from it's server path location – tandy Mar 20 '19 at 08:03
  • I can save the file as csv. But how download-csv routing will come to know that the user want to download a particular file.If many users are accessing my website then it would create a problem. – Neha patel Mar 20 '19 at 13:39
  • This is sort of a question of user experience and your own design. If a user uploads only 1 time, then you store an Id in their session, or alongside their user in a database somewhere. You can basically have another table that is user_files, or something like that, and you can link files to users on the backend. Then, when the user requests to download a file, you know which one to grab, because you can get all/one/or the latest file that the user created... – tandy Mar 20 '19 at 18:57