preview and download documents

I am trying to allow the user to preview and download ulpoaded documents to the db, but i keep getting

ValueError: read of closed file

when i open from the admin and click on the document it opens in the browser.

views.py

def preview_file(request, file_id):
    converted_file = get_object_or_404(OutputFile, id=file_id)

    print(f"converted: {converted_file}")
    print(f"converted_path: {converted_file.file.path}")

    # Assuming the file is stored in 'media/converted' directory
    file_path = converted_file.file.path

    # Open the file and return it as a response
    with open(file_path, 'rb') as file:
        response = FileResponse(file)
        return response

def download_file(request, file_id):
    converted_file = OutputFile.objects.get(id=file_id)

    # Assuming the file is stored in 'media/converted' directory
    file_path = converted_file.file.path

    # Open the file and return it as a response with content-disposition set for download
    with open(file_path, 'rb') as file:
        response = FileResponse(file)
        response['Content-Disposition'] = f'attachment; filename="{converted_file.filename}"'
        return response

terminal:

Traceback (most recent call last):
File "/usr/local/lib/python3.9/wsgiref/handlers.py", line 138, in run
self.finish_response()
File "/usr/local/lib/python3.9/wsgiref/handlers.py", line 183, in finish_response
for data in self.result:
File "/usr/local/lib/python3.9/wsgiref/util.py", line 37, in __next__
data = self.filelike.read(self.blksize)
ValueError: read of closed file
[11/Nov/2023 15:37:05] "GET /preview/b68230a0-b209-443f-93d4-dc1e3574c0fc/ HTTP/1.1" 500 59

Because you’re using context manager when openning file (with open(...)), the file is closed as soon as the view function exists (i.e. when returning the FileResponse object).

The FileResponse will try to consume the file after the view function returns, but it can’t as the file has been closed before.

Just update your code to remove context manager (e.g. file = open(...)) (see documentation for FileResponse : Request and response objects | Django documentation | Django). You do not need to worry about closing file, FileResponse (or wsgi.file_wrapper) will take care of that for you.

Side note: you do not need to handle Content-Disposition manually as you do. FileResponse constructor has parameters for that (see documentation link above)

Also, I do not have your model definition but I assume that OutputFile.file is a FileField. If so you should be able to use directly FileResponse(converted_file.file).

This implementation would have the benefit of being independent from the storage backend. Here, by using converted_file.file.path and open, you assume that backend storage is a FileSystemStorage. If you change the storage backend in the future for another one (e.g. s3 storage), your view implementation will fail