Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File download inside django-unicorn #486

Open
rjlinuxekoos opened this issue Nov 23, 2022 · 4 comments
Open

File download inside django-unicorn #486

rjlinuxekoos opened this issue Nov 23, 2022 · 4 comments

Comments

@rjlinuxekoos
Copy link

Hi!
I'm trying to download PDF files from the django runserver development server, "python manager.py runserver", inside a django-unicorn application, but I can't download them. Follow the code >
with open(os.path.join("c:/mydirectory/tmp", filename + '.pdf'), 'rb') as f:
data = f.read()

            response = HttpResponse(data, content_type='application/pdf')
            response['Content-Disposition'] = 'attachment; filename="' + filename + '.pdf"'
            
            return response

No error occurs, but accessing from another machine I can't download.
Is there any way to be reproduced?
Thanks!

@adamghill
Copy link
Owner

Where is this code? Is it inside a Unicorn component or somewhere else? If you can create a repo that demonstrates the problem I can take a look at it. Thanks!

@pa-hqt
Copy link

pa-hqt commented Dec 4, 2023

Hello @adamghill,
I think I have a similiar feature request and created a minimal example based on your repository:
https://github.com/pa-hqt/django-unicorn/tree/example/file-download
Run server and visit http://localhost:8000/file-response

I would like to be able to provide a dynamically created file, when user clicks on a download button. To create the file, I need data that exist within the unicorn component.

My stupid approach was to call an action method that returns a FileResponse (like you can return HttpResponseRedirect), but unfortunately that crashes with following exception:

Type is not JSON serializable: FileResponse
TypeError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "\django-unicorn\django_unicorn\views\objects.py", line 157, in get_data
    serialized_value = loads(dumps(self.value))
  File "\django-unicorn\django_unicorn\serializer.py", line 414, in dumps
    serialized_data = orjson.dumps(data, default=_json_serializer)
TypeError: Type is not JSON serializable: FileResponse

If there is another possible approach, I would be thankful to get advice. Maybe I can access the UnicornView instance from the outer/wrapping django view?

@adamghill
Copy link
Owner

I think your inclination to return FileResponse makes sense -- it feels intuitive to me at least. But, I'll need to build something into Unicorn to support it. I explicitly handle the redirect response, convert it into JSON, and then do specific things client-side in JavaScript so it all feels seamless.

How big is the file? Is it reasonable for Unicorn to store it in a cache server-side? Or in a temporary directory?

I think one potential workflow would be:

  1. Component action creates the file
  2. Component returns FileResonse
  3. Unicorn takes file bytes, stores in temp directory with a unique identifier, passes that unique identifier back to the client in JSON
  4. JS makes a call the server with unique identifier
  5. Server responds with actual file read from temporary file

@pa-hqt
Copy link

pa-hqt commented Dec 5, 2023

In my case it will be an Excel file with a size of 200-600KB, but I think larger files of 10MB or so should be supported too. In general the temporary directory should be

Your workflow sounds sensible. Some comments that come to my mind:

  • By comsuming the FileResponse (to write it to temp. file), sending the identifier and trigger a second request to consume the file again, you create an extra request roundtrip. But you achieve that the file size is nearly irrelevant.
  • For small files it might be a solution to return the encoded bytes in the first response, but that has other disadvantages:
    • File streaming is not possible, which limits the reasonable file size that can be handled
    • File handling in JS might be another difficulty

Thank you for considering this for your nice project

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants