0

I am creating a flask app that takes a CSV as input. Parses the CSV and the content. Then returns an updated CSV to the browser to download/or instantly downloads. The program needs an HTML template for users to interact. I am attempting to use the render_template() method to return the HTML file and the CSV file via flask. What is the best way to achieve this?

@app.route("/", methods=["GET", "POST"])
def index():
        if request.method == "POST":
    print("POST request received!")

    if "file" not in request.files:
        return redirect(request.url)

    list_keywords = request.files["file"]
    if not list_keywords:
        return "No file"
    the_list = io.StringIO(list_keywords.stream.read().decode("UTF8"), newline=None)
    csv_input = csv.reader(the_list)
    ...# rest of program.....
    csv_file1 = pd.DataFrame(internal_linking_opportunities,
                                     columns=["Keyword", "Text", "Source URL", "Target URL", "Link Presence", "Keyword Position"])

si = io.StringIO()
cw = csv.writer(csv_file1)
output = make_response(si.getvalue())
output.headers["Content-Disposition"] = "attachment; filename=export.csv"
output.headers["Content-type"] = "text/csv"


return Response(render_template('index.html', output=output))

I have attempted to use other methods to return the CSV with no luck. Starting to think it could be due to the render_template function that I am using. Your help is appreciated.

1 Answers1

1

The second parameter of render_template is called context and can be used to provide the template with some variables for rendering. Adding a Response object to the templates context is not going to return that Response, but instead make that Response object accessible from within the template.

Flask has a dedicated method for sending files back to the browser:

https://flask.palletsprojects.com/en/1.1.x/api/#flask.send_file

Your return statement could look something like this:

return send_file(file_pointer, as_attachment=True, attachment_filename="export.csv")

Instead of providing the file pointer as the first argument, you can also use a file from your local disk by providing the path to that file. If you provide the file pointer, make sure to set it to the start of the file.

Chris Meh
  • 196
  • 1
  • 3
  • Thank you for your answer! I am new to Flask and Python so your help is greatly appreciated. Since I also want to POST my index.html file to the browser how can I accomplish both in the same return call? Or will I have to set the render template return in a separate Def function? Hopefully that makes sense and I am not being too confusing! – Michael_at_Webfor Mar 30 '21 at 20:10
  • Yeah, you will need to add a separate view function / route. You can't both display a regular HTML page and initiate a download at the same time, at least from a technical point of view. You could utilize some JavaScript to get a similar user experience, though. – Chris Meh Mar 31 '21 at 15:18