Para futuras referencias: acabo de tener el caso en el que no podía usar archivos temporales para las descargas. Pero igual tenía que eliminarlos después; así que así es como lo hice (realmente no quería confiar en cron jobs o apio o wossnames, es un sistema muy pequeño y quería que siguiera siendo así).
def plug_cleaning_into_stream(stream, filename):
try:
closer = getattr(stream, 'close')
#define a new function that still uses the old one
def new_closer():
closer()
os.remove(filename)
#any cleaning you need added as well
#substitute it to the old close() function
setattr(stream, 'close', new_closer)
except:
raise
y luego acabo de tomar el flujo utilizado para la respuesta y enchufado en él.
def send_file(request, filename):
with io.open(filename, 'rb') as ready_file:
plug_cleaning_into_stream(ready_file, filename)
response = HttpResponse(ready_file.read(), content_type='application/force-download')
# here all the rest of the heards settings
# ...
return response
Sé que esto es rápido y sucio, pero funciona. Dudo que sea productivo para un servidor con miles de solicitudes por segundo, pero ese no es mi caso aquí (máximo unas pocas docenas por minuto).
EDITAR: Olvidé precisar que estaba tratando con archivos muy grandes que no cabían en la memoria durante la descarga. Es por eso que estoy usando un BufferedReader
(que es lo que está debajo de io.open()
)
'el archivo temporal debe eliminarse una vez que se ha expulsado el objeto newfile': ¿hay un mecanismo incorporado para eliminar automáticamente las instancias' NamedTemporaryFile'? –
si estoy en lo cierto, los objetos son destruidos por el recolector de basura una vez que se destruyen todas las referencias a él. Cuando salga de la función send_file, no debería haber más referencias al objeto newfile, por lo tanto, podría eliminarse la próxima vez que se ejecute el GC. El destructor de NamedTemporaryFile afirma: def cerca de (auto): si no self.close_called: self.close_called = True self.file.close() self.unlink (self.name) def __del __ (self): self.close() – fylb
fylb, tienes razón, pero no está garantizado que el objeto será recogido como basura y se invoca su método __del__. ¿Quién sabe qué hará el recolector de basura? Es mejor limpiarlo manualmente de forma periódica. – loevborg