I have a Django project which involves a user uploading a CSV file via a form. I parse this file in the forms clean
method, and then in the views form_valid
method I want to read the file data again (for the purposes of long term storage).
My issue is that after parsing the file in the clean
method, I'm no longer able to perform IO operations on the file object, any attempt to do so raises an error. Code as below:
class MyForm(forms.Form):
file = forms.FileField()
def clean(self):
cleaned_data = super().clean()
file = cleaned_data["file"]
reader = csv.DictReader(io.TextIOWrapper(file))
for row in reader:
... # process data
return cleaned_data
class MyView(generic.FormView):
form_class = MyForm
def form_valid(self, form):
file = form.files["file"]
file.read() # raises ValueError: I/O operation on closed file.
At this point it's no longer possible to call other methods like file.open()
either as this leads to the same exception being raised.
What I am finding confusing about this is that there are other examples in my application of where IO operations can be performed on the file in the form_valid
method, example below:
class MyOtherForm(forms.Form):
file = forms.FileField()
class MyOtherView(generic.FormView):
form_class = MyOtherForm
def form_valid(self, form):
file = form.files["file"]
file.read() # this works, no error raised.
My interpretation of this is that somehow the process of reading the file is what triggers it to be closed, although I am not sure where or how. What I want to know is if there is any way I can prevent the file from closing after I read it, or reopen the file after it has closed?
I realise I could perform both the initial read/parse and the second one inside the same method and this should solve my issue. However, at that point I'm starting to tangle my concerns so would prefer to avoid it.
It turns out the problem was the use of the io.TextIOWrapper
, it was resolved by calling the detach
method on the text wrapper before it was cleaned up.
A more detailed explanation is covered in this other SO post: Why is TextIOWrapper closing the given BytesIO stream?