Django FileResponse: PermissionError: [WinError 32] Процесс не может получить доступ к файлу, потому что он используется другим процессом
Я пытался вернуть файл с помощью django FileResponse, но столкнулся с проблемой: экземпляр файла не может быть удален после отправки ответа. До этой реализации я использовал модуль tempfile, но он также не работал.
from rest_framework import views, status
from django.http import FileResponse
import os
class DownloadShoppingCartView(views.APIView):
def get(self, request):
try:
with open('test.txt', 'w+') as file:
file.write('supertest\n')
return FileResponse(
open(file.name, mode='rb'),
as_attachment=True,
status=status.HTTP_200_OK
)
except Exception as e:
print('There will be exception handling')
finally:
"""I also have been trying to put here time.sleep(5),
but there was no positive result.
"""
os.remove(file.name)
Полное отслеживание:
Internal Server Error: /api/recipes/download_shopping_cart/
Traceback (most recent call last):
File "C:\Users\Justm\dev\foodgram-project-react\backend\.venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\Justm\dev\foodgram-project-react\backend\.venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Justm\dev\foodgram-project-react\backend\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Users\Justm\dev\foodgram-project-react\backend\.venv\lib\site-packages\django\views\generic\base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\Justm\dev\foodgram-project-react\backend\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "C:\Users\Justm\dev\foodgram-project-react\backend\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "C:\Users\Justm\dev\foodgram-project-react\backend\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
raise exc
File "C:\Users\Justm\dev\foodgram-project-react\backend\.venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "C:\Users\Justm\dev\foodgram-project-react\backend\recipes\views.py", line 141, in get
os.remove(file.name)
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'test.txt'
Пункт finally
выполняется перед пунктом return
.
Поскольку вы open(file.name, mode='rb')
, который будет закрыт только после return
и отправки ответа, os.remove
в пункте finally
не может получить доступ к файлу.
Вы можете реализовать прокси для удаления файлов после закрытия.
import os
from django.core.files.utils import FileProxyMixin
class RemoveAfterCloseFileProxy(FileProxyMixin):
def __init__(self, file):
self.file = file
self.name = file.name
def close(self):
if not self.closed:
self.file.close()
try:
os.remove(self.name)
except FileNotFoundError:
pass
def __del__(self):
self.close()
Использование:
class DownloadShoppingCartView(views.APIView):
def get(self, request):
try:
with open('test.txt', 'w+') as file:
file.write('supertest\n')
return FileResponse(
# open(file.name, mode='rb'), # Change this
RemoveAfterCloseFileProxy(open(file.name, mode='rb')), # to this
as_attachment=True,
status=status.HTTP_200_OK
)
except Exception as e:
print('There will be exception handling')
finally:
# os.remove(file.name) # Wrap this
try: # in try-except
os.remove(file.name) #
except PermissionError: #
pass #