Reputation: 826
I have a Flask backend which generates an image based on some user input, and sends this image to the client side using the send_file()
function of Flask.
This is the Python server code:
@app.route('/image',methods=['POST'])
def generate_image():
cont = request.get_json()
t=cont['text']
print(cont['text'])
name = pic.create_image(t) //A different function which generates the image
time.sleep(0.5)
return send_file(f"{name}.png",as_attachment=True,mimetype="image/png")
I want to delete this image from the server after it has been sent to the client.
How do I achieve it?
Upvotes: 2
Views: 3269
Reputation: 385
After trying all the methods:
This is useful to modify response objects. The function is passed the response object and has to return the same or a new one.
ie it is run before the request is returned to modify the response, hence it is no different from adding that code at the end of the function instead of return. This only works in Linux because file pointers can exist even after file deletion there.
So what I found best is to open the image as a file object to read the contents,delete the file and sent this contents over
with open(f"{name}.png", 'rb') as f:
contents = f.read()
os.remove(f"{name}.png")
return send_file(
io.BytesIO(contents),
as_attachment=True,
attachment_filename=f"{name}.png",
mimetype="image/png"
)
Upvotes: 2
Reputation: 90
I had the same issues as some other commenters here:
Finally I came up with a solution (sorry the example is from my code, so a little bit different from the original question):
@bp.route('/download/<int:id>')
def download(id: int):
with db.session() as ses:
data = ses.scalars( ... fetch data from db by id...).one_or_none()
if session_data is None:
abort(404, f"Data with id {id} unknown.")
try:
with tempfile.NamedTemporaryFile(delete=False, suffix=".tmp") as fid:
tmp_file = Path(fid.name)
write_data_to_file(tmp_file, data)
fid.seek(0)
file_content = io.BytesIO(fid.read())
finally:
tmp_file.unlink()
return send_file(
file_content,
"application/octet-stream",
as_attachment=True,
download_name=f"Data_{id}.tmp")
This will write the data fetched from db to a file (unfortunatey the writer function in my case only accepts file names...). Since my code must also run on Windows, I need to do the delete=False ... .unlink() trick. If this weren't the case, one could also just let the context manager do the job.
The actual solution is in reading the file content into an io.BytesIO buffer and then closing and deleting the file before returning.
Upvotes: 0
Reputation: 61
Another way would be to include the decorator in the route. Thus, you do not need to check for the endpoint. Just import after_this_request
from the flask
lib.
from flask import after_this_request
@app.route('/image',methods=['POST'])
def generate_image():
@after_this_request
def delete_image(response):
try:
os.remove(image_name)
except Exception as ex:
print(ex)
return response
cont = request.get_json()
t=cont['text']
print(cont['text'])
name = pic.create_image(t) //A different function which generates the image
time.sleep(0.5)
return send_file(f"{name}.png",as_attachment=True,mimetype="image/png")
Upvotes: 2
Reputation: 826
Ok I solved it. I used the @app.after_request
and used an if condition to check the endpoint,and then deleted the image
@app.after_request
def delete_image(response):
global image_name
if request.endpoint=="generate_image": //this is the endpoint at which the image gets generated
os.remove(image_name)
return response
Upvotes: 5
Reputation: 42
You could have another function delete_image() and call it at the bottom of the generate_image() function
Upvotes: -2