1

我一直在尝试使用 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'
4

1 回答 1

0

finally子句在return.

由于 you ,只有在响应发送open(file.name, mode='rb')后才会关闭,因此在子句中无法访问文件。returnos.removefinally

您可以实现关闭后删除文件代理。

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                  #
于 2021-09-25T18:57:47.763 回答