Suraj Palwe Suraj Palwe - 4 years ago 299
Python Question

send_file() when called return text document instead of an image

I want to send an image file from server side to client side. I am using flask framework.

But the problem is whenever I call the route in which

send_file()
is, the response return is an File. When I click this file gedit opens it with nothing in that file. That means it must be text file written.

I referred the flask docs for
send_file()
.

Here is what I am doing in the code:

@app.route('/try')
def trial():
todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'
resp = requests.get(todown)
return send_file(resp,mimetype="image/jpeg",attachment_filename="img.jpg",as_attachment=True)


Whenever I load
localhost:5000/try
a file is downloaded but not the image file that I want to download.

Error I am getting in my terminal is
AttributeError: 'Response' object has no attribute 'read' error


What must be the problem. Is anything missing in this above snippet?

Answer Source
  1. resp is a requests.models.Response object, not string or bytes:

    >>> import requests
    >>> todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'
    >>> resp = requests.get(todown)
    >>> resp
    <Response [200]>
    >>> type(resp)
    <class 'requests.models.Response'>
    >>> 
    
  2. Flask.send_file() send a file.


So fist at all you need use resp.content to get the content of the object, it'll return bytes object(and by the way, resp.text return string object. Always use .content if you're downloading an image, video, or other non-text things).

Please check the document for more details.


Then, because Flask.send_file() send a file, so you need write the image into a file before you send it.

For example:

import requests
from flask import Flask, send_file

app = Flask(__name__)

@app.route('/')
def tria():
    todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'
    resp = requests.get(todown)
    with open('image', 'wb') as f:
        f.write(resp.content)

    return send_file('image', mimetype="image/jpeg", attachment_filename="img2.jpg", as_attachment=True)

app.run(port=80, debug=True)

You can also use io.BytesIO here, then you don't need delete that image after you sent it. And note that use io.StringIO if you're sending a text file.

For example:

import requests
from io import BytesIO
from flask import Flask, send_file

app = Flask(__name__)

@app.route('/')
def tria():
    todown = 'https://igcdn-photos-e-a.akamaihd.net//hphotos-ak-xaf1//t51.2885-15//e35//12093691_1082288621781484_1524190206_n.jpg'
    resp = requests.get(todown)
    return send_file(BytesIO(resp.content), mimetype="image/jpeg", attachment_filename="img2.jpg", as_attachment=True)

app.run(port=80, debug=True)

Both work fine.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download