Как я могу передать строку в метод .close() объекта FileResponse?

#python #python-3.x #django #class #web

Вопрос:

Я изменяю поведение метода .close() объекта FileResponse. FileResponse-это подкласс StreamingHttpResponse, который очень похож на объект HttpResponse.

То, что я пытаюсь сделать, это взять строку текста, сохранить ее в файле .docx, отправить этот документ в браузер, а затем удалить этот документ. Все работает отлично, пока я не попытаюсь удалить .docx. Не похоже, что я могу удалить файл до отправки ответа, потому что ответ нуждается в файле, но я вообще ничего не могу сделать после отправки ответа, потому что представление выполнило свою задачу и отправило ответ. Потенциальным решением, которое я нашел, является изменение метода .close() объекта FileResponse (аналогично объекту HttpResponse) для удаления файла.

Здорово. Однако я не знаю, как передать путь к файлу методу .close (). Это может быть элементарный вопрос, но я обычно избегаю редактирования встроенных методов класса.

Код ниже.

 import logging
from django.http import FileResponse
import os  

logger = logging.getLogger("django")

#editing the default closing behavior of the file response object to delete the file 
that it just sent.
class SendAndDeleteExport(FileResponse):
    def close(self):
        super(SendAndDeleteExport, self).close()
        # do whatever you want, this is the last codepoint in request handling
        logger.info(self)
        # os.remove(desired_path   "/export.docx"

        if self.status_code == 200:
            logger.info('HttpResponse successful: %s' % self.status_code)
 

Я получаю «HttpResponse успешно: 200» в консоли, поэтому я знаю, что добиваюсь некоторого прогресса, но мне нужно передать путь к файлу из представления в this .close()

views.py

 from .helpers import SendAndDeleteExport
from docx import Document
import os

def export(request):
    cwd = os.getcwd()
    desired_path = os.path.join(cwd, 'exports')
    logger.info(desired_path)
    document = Document()
    paragraph = document.add_paragraph('Lorem ipsum dolor sit amet.  edited againa')
    document.save(desired_path   "/export.docx")
    file_to_user = SendAndDeleteExport(open(desired_path   "/export.docx", 'rb'))
    return file_to_user
 

Файл .docx действительно создается и отправляется клиенту в качестве загрузки, что является желаемым поведением, но я не хочу держать все эти экспортированные файлы бесконечно.

Ответ №1:

Вы можете использовать request_finished объединение сигналов с объектом изоляции потоков local для достижения такого удаления файла после успешного ответа. сигналы джанго: https://docs.djangoproject.com/en/3.2/ref/signals/#request-finished

django.core.signals.request_finished Отправляется, когда Django завершает доставку HTTP-ответа клиенту.

для получения более подробной информации, пожалуйста, смотрите: https://docs.djangoproject.com/en/3.2/topics/signals/

 from threading import local

from django.core.signals import request_finished
from django.shortcuts import HttpResponse

local = local()  # for threading isolation 

def export(request):
    # do something
    local.path = 'your_file_path'
    return HttpResponse('ok')

def when_request_finished(sender, **kwargs):
    """
    this function will be executed when any request finished(got response)
    """
    if hasattr(local, 'path'):
        # do something
        print(local.path)

request_finished.connect(when_request_finished, dispatch_uid="when_request_finished_identifier")