upload.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. from typing import Any, Callable, Dict, Optional
  2. from fastapi import Request
  3. from starlette.datastructures import UploadFile
  4. from ..dependencies import register_component
  5. from ..events import EventArguments, UploadEventArguments, handle_event
  6. from ..nicegui import app
  7. from .mixins.disableable_element import DisableableElement
  8. register_component('upload', __file__, 'upload.js')
  9. class Upload(DisableableElement):
  10. def __init__(self, *,
  11. multiple: bool = False,
  12. max_file_size: Optional[int] = None,
  13. max_total_size: Optional[int] = None,
  14. max_files: Optional[int] = None,
  15. on_upload: Optional[Callable[..., Any]] = None,
  16. on_rejected: Optional[Callable[..., Any]] = None,
  17. label: str = '',
  18. auto_upload: bool = False,
  19. ) -> None:
  20. """File Upload
  21. Based on Quasar's `QUploader <https://quasar.dev/vue-components/uploader>`_ component.
  22. :param multiple: allow uploading multiple files at once (default: `False`)
  23. :param max_file_size: maximum file size in bytes (default: `0`)
  24. :param max_total_size: maximum total size of all files in bytes (default: `0`)
  25. :param max_files: maximum number of files (default: `0`)
  26. :param on_upload: callback to execute for each uploaded file (type: nicegui.events.UploadEventArguments)
  27. :param on_rejected: callback to execute for each rejected file
  28. :param label: label for the uploader (default: `''`)
  29. :param auto_upload: automatically upload files when they are selected (default: `False`)
  30. """
  31. super().__init__(tag='upload')
  32. self._props['multiple'] = multiple
  33. self._props['label'] = label
  34. self._props['auto-upload'] = auto_upload
  35. self._props['url'] = f'/_nicegui/client/{self.client.id}/upload/{self.id}'
  36. if max_file_size is not None:
  37. self._props['max-file-size'] = max_file_size
  38. if max_total_size is not None:
  39. self._props['max-total-size'] = max_total_size
  40. if max_files is not None:
  41. self._props['max-files'] = max_files
  42. @app.post(self._props['url'])
  43. async def upload_route(request: Request) -> Dict[str, str]:
  44. for data in (await request.form()).values():
  45. assert isinstance(data, UploadFile)
  46. args = UploadEventArguments(
  47. sender=self,
  48. client=self.client,
  49. content=data.file,
  50. name=data.filename or '',
  51. type=data.content_type or '',
  52. )
  53. handle_event(on_upload, args)
  54. return {'upload': 'success'}
  55. if on_rejected:
  56. self.on('rejected', lambda _: handle_event(on_rejected, EventArguments(sender=self, client=self.client)),
  57. args=[])
  58. def reset(self) -> None:
  59. self.run_method('reset')
  60. def delete(self) -> None:
  61. app.remove_route(self._props['url'])
  62. super().delete()