I built a form with a FileField in order to upload file to be processed. Strangely it seem that file is closed before I can do anything with in the view. I encounter a ValueError after validating the form:
"I/O operation on closed file"
I can see that file is properly detected but closed when attempting to read it.
Note: Django version 2.2.25.
forms.py
class FileImportForm(forms.Form):
headers = ["lastname","firstname","gender","title","entity","email","company","address","phone"]
file = forms.FileField(label='CSV file',validators=[CsvFileValidator(headers)])
def clean_file(self):
file = self.cleaned_data['file']
return file
views.py
#login_required
def file_import(request):
if request.method == 'POST':
form = FileImportForm(request.POST,request.FILES)
if form.is_valid():
if request.FILES['file']:
file_post = request.FILES['file']
# Offending line below (I/O operation on closed file)
file_content = file_post.read().decode('UTF-8')
return redirect("/foo")
else:
form = FileImportForm()
return render(request,"file_import.html", { 'form': form })
How to properly process uploaded file (read, etc..)?
The error occurs because you didn't open your file properly. Here's the working way:
file_post = request.FILES['file']
f = open(file_post, "w")
As python's file operation also comes with a read-only method, you cannot do file_content = file_post.read().decode('UTF-8') directly because you didn't make this file writable.
Reference.
EDIT
As the upload file type may be incorrect, more conversions are needed. Something like:
def my_view(request):
uploaded_file = request.FILES['file']
str_text = ''
for line in uploaded_file:
str_text = str_text + line.decode() # "str_text" will be of `str` type
# do something
return something
Reference2
Related
I am using below code where I am using PUT api from POSTMAN to send a file to a machine hosting the api using python script
#app.route('/uploadFIle', methods=['PUT'])
def uploadFile():
chunk_size = 4096
with open("/Users/xyz/Documents/filename", 'wb') as f:
while True:
chunk = request.stream.read(chunk_size)
if len(chunk) == 0:
break
f.write(chunk)
return jsonify({"success":"File transfer initiated"})
Is there a way to get the original filename so that I can use the same while saving the file ?
Can do as below by passing name from PUT api itself, but is it the best solution ?
#app.route('/uploadFIle/<string:filename>', methods=['PUT'])
def uploadFile(filename):
Below is how I achieved it using flask -
Choose form-data under body in POSTMAN
You can give any key, i used 'file' as key, then choose option 'file' from drop down arrow in key column
Attach file under 'value' column and use below code to get the file name -
from flask import request
file = request.files['file']
file_name = file.filename
This question already has an answer here:
Remove file after Flask serves it
(1 answer)
Closed 1 year ago.
I want my server to send a file to the user, and then delete the file.
The problem is that in order to return the file to the user, i am using this:
return send_file(pathAndFilename, as_attachment=True, attachment_filename = requestedFile)
Since this returns, how can i delete the file from the os with os.remove(pathAndFilename)?
I also tried this:
send_file(pathAndFilename, as_attachment=True, attachment_filename = requestedFile)
os.remove(pathAndFilename)
return 0
But i got this error:
TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a int.
Since send_file already returns the response from the endpoint, it is no longer possible to execute code afterwards.
However, it is possible to write the file to a stream before the file is deleted and then to send the stream in response.
from flask import send_file
import io, os, shutil
#app.route('/download/<path:filename>')
def download(filename):
path = os.path.join(
app.static_folder,
filename
)
cache = io.BytesIO()
with open(path, 'rb') as fp:
shutil.copyfileobj(fp, cache)
cache.flush()
cache.seek(0)
os.remove(path)
return send_file(cache, as_attachment=True, attachment_filename=filename)
In order to achieve better use of the memory for larger files, I think a temporary file is more suitable as a buffer.
from flask import send_file
import os, shutil, tempfile
#app.route('/download/<path:filename>')
def download(filename):
path = os.path.join(
app.static_folder,
filename
)
cache = tempfile.NamedTemporaryFile()
with open(path, 'rb') as fp:
shutil.copyfileobj(fp, cache)
cache.flush()
cache.seek(0)
os.remove(path)
return send_file(cache, as_attachment=True, attachment_filename=filename)
I hope your conditions are met.
Have fun implementing your project.
dirLocation = "Patients Data/PatientsTimelineLog.csv"
try:
if os.path.isfile(dirLocation):
print("Directory exist." + dirLocation)
else:
print("Directory does not exists. Creating new one." + dirLocation)
os.makedirs(os.path.dirname(dirLocation))
except IOError:
print("Unable to read config file and load properties.")
Automatically creating directories with file output
Want to create a PatientsTimelineLog.csv inside Patients Data folder in one go if it does not exist. The above link is creating the folder but the csv file is not made. makedir is used to make directory but i want inside the file in it like the path given above in dirLocation.
Inside the else, you can directly use os.makedirs(dirLocation).
When you use os.path.dirname(dirLocation) you are selecting everything except the name of the csv file. That is why you are creating only the folder.
try:
folder_path = os.path.split(os.path.abspath(dirLocation))
sub_path = folder_path[0]
if os.path.isdir(sub_path):
print("Directory exist: " + dirLocation)
else:
print("Directory does not exists. Creating new one: " + dirLocation)
file_name = PurePath(dirLocation)
obj = file_name.name
filepath = os.path.join(sub_path, obj)
os.makedirs(sub_path)
f = open(filepath, "a")
except IOError:
print("Unable to read config file and load properties.")
This is the answer to my question. pathlib did lot of help in this question
def a():
import json
path=open('C:\\Users\\Bishal\\code\\57.json').read()
config=json.load(path)
for key in config:
return key
You have already read the file path=open('C:\Users\Bishal\code\57.json').read(), so when you try to load with json.load(path), the file pointer is at the end of the file; hence nothing gets loaded or parsed.
Either load the file directly into json, or read the contents and then parse the string with json.loads (note the s)
Option 1:
path = open(r'C:\Users\Bishal\code\57.json').read()
config = json.loads(path)
Option 2:
path = open(r'C:\Users\Bishal\code\57.json')
config = json.load(path)
path.close()
Then you can do whatever you like with the result:
for key,item in config.items():
print('{} - {}'.format(key, item))
How come it's not opening the file I put into the function? It opens when I plug the file name directly into the main program, but not when I try to pass it through the function. It gives me a FileNotFoundError.
def get_valid_filename(prompt):
'''Use prompt (a string) to ask the user to type the name of a file. If
the file does not exist, keep asking until they give a valid filename.
Return the name of that file.'''
filename = input(prompt)
if os.path.isfile(filename) == False:
print ("That file does not exist.")
filename = input(prompt)
return filename
if __name__ == '__main__':
prompt = 'enter the name of the file with unknown author:'
mystery_filename = get_valid_filename(prompt)
# readlines gives us the file as a list of strings each ending in '\n'
text = open(mystery_filename, 'r').read()
print (text)
get_valid_filename should look like this:
def get_valid_filename(prompt):
while True:
filename = input(prompt):
if os.path.exists(filename):
return filename
print('that file does not exist')