drf-chunked-upload


Namedrf-chunked-upload JSON
Version 0.6.0 PyPI version JSON
download
home_pagehttps://github.com/jkeifer/drf-chunked-upload
SummaryUpload large files to Django REST Framework in multiple chunks, with the ability to resume if the upload is interrupted.
upload_time2023-08-13 02:54:36
maintainer
docs_urlNone
authorJarrett Keifer
requires_python>3.7
licenseMIT-Zero
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # drf-chunked-upload

[![test-status-image]][test-status]
[![coverage-status-image]][codecov]
[![pypi-version]][pypi]

This simple django app enables users to upload large files to Django Rest
Framework in multiple chunks, with the ability to resume if the upload is
interrupted.

This app is based to a large degree on the work of [Julio Malegria][github-jm],
specifically his [django-chunked-upload app][dcu].

License: [MIT-Zero][lic].

## Installation

Install via pip:

```shell
pip install drf-chunked-upload
```

And then add it to your Django `INSTALLED_APPS`:

```shell
INSTALLED_APPS = (
    # ...
    'drf_chunked_upload',
)
```

## Typical usage

1. An initial PUT request is sent to the url linked to `ChunkedUploadView` (or
   any subclass) with the first chunk of the file. The name of the chunk file
   can be overriden in the view (class attribute `field_name`). Example:

   ```python
   r = requests.put(
       upload_url,
       headers={
           "Content-Range": "bytes {}-{}/{}".format(index, index + size - 1, total),
       },
       data={"filename": build_file},
       files={'file': chunk_data},
   )
   ```

2. In return, the server will respond with the `url` of the upload, and the
   current `offset`. Example:

   ```python
   {
       'id': 'f64ebd67-83a3-45b6-8acd-c749ea1ed4cd'
       'url': 'https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd',
       'file': 'https://your-host/<path_to_file>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd.part',
       'filename': 'example.bin',
       'offset': 10000,
       `created_at`: '2021-05-18T17:12:50.318718Z',
       'status': 1,
       'completed_at': None,
       'user': 1
   }
   ```

3. Repeatedly PUT subsequent chunks to the `url` returned from the server.
   Example:

   ```python
   # PUT to https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd
   upload_url = "https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd"
   r = requests.put(
       upload_url,
       headers={
           "Content-Range": "bytes {}-{}/{}".format(index, index + size - 1, total),
       },
       data={"filename": build_file},
       files={'file': chunk_data},
   )
   ```

4. Server will continue responding with the `url` and current `offset`.
5. Finally, when upload is completed, POST a request to the returned `url`.
   This request must include the checksum (hex) of the entire file. Example:

   ```python
   # POST to https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd
   upload_url = "https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd"
   r = requests.post(upload_url, data={"md5": "fc3ff98e8c6a0d3087d515c0473f8677"})
   ```

6. If everything is OK, server will response with status code 200 and the data
   returned in the method `get_response_data` (if any).

If you want to upload a file as a single chunk, this is also possible! Simply
make the first request a POST and include the checksum digest for the file. You
don't need to include the `Content-Range` header if uploading a whole file.

If you want to see the list of pending chunked uploads, make a `GET` request to
the URL linked to `ChunkedUploadView` (or any subclass). You will get a list of
pending chunked uploads (for the currently authenticated user only).

**Possible error responses:**

- Upload has expired. Server responds 410 (Gone).
- `id` does not match any upload. Server responds 404 (Not found).
- No chunk file is found in the indicated key. Server responds 400 (Bad
  request).
- Request does not contain `Content-Range` header. Server responds 400 (Bad
  request).
- Size of file exceeds limit (if specified). Server responds 400 (Bad request).
- Offsets do not match. Server responds 400 (Bad request).
- Checksums do not match. Server responds 400 (Bad request).

## Settings

Add any of these variables into your project settings to override them.

`DRF_CHUNKED_UPLOAD_EXPIRATION_DELTA`

- How long after creation the upload will expire.
- Default: `datetime.timedelta(days=1)`

`DRF_CHUNKED_UPLOAD_PATH`

- Path where uploaded files will be stored.
- Default: `'chunked_uploads/%Y/%m/%d'`

`DRF_CHUNKED_UPLOAD_CHECKSUM`

- The type of checksum to use when verifying checksums. Options include
  anything supported by Python\'s hashlib (md5, sha1, sha256, etc)
- Default: `'md5'`

`DRF_CHUNKED_UPLOAD_COMPLETE_EXT`

- Extension to use for completed uploads. Uploads will be renamed using this
  extension on completion, unless this extension matched
  `DRF_CHUNKED_UPLOAD_INCOMPLETE_EXT`.
- Default: `'.done'`

`DRF_CHUNKED_UPLOAD_INCOMPLETE_EXT`

- Extension for in progress upload files.
- Default: `'.part'`

`DRF_CHUNKED_UPLOAD_STORAGE_CLASS`

- Storage system (should be a class)
- Default: `None` (use default storage system)

`DRF_CHUNKED_UPLOAD_USER_RESTRICED`

- Boolean that determines whether only the user who created an upload can
  view/continue an upload.
- Default: `True`

`DRF_CHUNKED_UPLOAD_ABSTRACT_MODEL`

- Boolean that defines if the `ChunkedUpload` model will be abstract or not
  ([what does abstract model mean?][abstract-model]).
- Default: `True`

`DRF_CHUNKED_UPLOAD_MAX_BYTES`

- Max amount of data (in bytes) that can be uploaded. `None` means no limit.
- Default: `None`

## Support

If you find any bug or you want to propose a new feature, please use the
[issues tracker][issues]. Pull requests are accepted.

[test-status-image]: https://github.com/jkeifer/drf-chunked-upload/actions/workflows/python-test.yml/badge.svg
[test-status]: https://github.com/jkeifer/drf-chunked-upload/actions/workflows/python-test.yml
[coverage-status-image]: https://img.shields.io/codecov/c/github/jkeifer/drf-chunked-upload/main.svg
[codecov]: https://codecov.io/github/jkeifer/drf-chunked-upload?branch=main
[pypi-version]: https://img.shields.io/pypi/v/drf-chunked-upload.svg
[pypi]: https://pypi.org/project/drf-chunked-upload/
[github-jm]: https://github.com/juliomalegria
[dcu]: https://github.com/juliomalegria/django-chunked-upload
[issues]: https://github.com/jkeifer/drf-chunked-upload/issues
[lic]: https://romanrm.net/mit-zero
[abstract-model]: https://docs.djangoproject.com/en/3.2/topics/db/models/#abstract-base-classes

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/jkeifer/drf-chunked-upload",
    "name": "drf-chunked-upload",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">3.7",
    "maintainer_email": "",
    "keywords": "",
    "author": "Jarrett Keifer",
    "author_email": "jkeifer0@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/bb/c7/5bfaf2cf519d0e7e8b476415ca7728db9fc10e993db15c016091559b45ff/drf-chunked-upload-0.6.0.tar.gz",
    "platform": null,
    "description": "# drf-chunked-upload\n\n[![test-status-image]][test-status]\n[![coverage-status-image]][codecov]\n[![pypi-version]][pypi]\n\nThis simple django app enables users to upload large files to Django Rest\nFramework in multiple chunks, with the ability to resume if the upload is\ninterrupted.\n\nThis app is based to a large degree on the work of [Julio Malegria][github-jm],\nspecifically his [django-chunked-upload app][dcu].\n\nLicense: [MIT-Zero][lic].\n\n## Installation\n\nInstall via pip:\n\n```shell\npip install drf-chunked-upload\n```\n\nAnd then add it to your Django `INSTALLED_APPS`:\n\n```shell\nINSTALLED_APPS = (\n    # ...\n    'drf_chunked_upload',\n)\n```\n\n## Typical usage\n\n1. An initial PUT request is sent to the url linked to `ChunkedUploadView` (or\n   any subclass) with the first chunk of the file. The name of the chunk file\n   can be overriden in the view (class attribute `field_name`). Example:\n\n   ```python\n   r = requests.put(\n       upload_url,\n       headers={\n           \"Content-Range\": \"bytes {}-{}/{}\".format(index, index + size - 1, total),\n       },\n       data={\"filename\": build_file},\n       files={'file': chunk_data},\n   )\n   ```\n\n2. In return, the server will respond with the `url` of the upload, and the\n   current `offset`. Example:\n\n   ```python\n   {\n       'id': 'f64ebd67-83a3-45b6-8acd-c749ea1ed4cd'\n       'url': 'https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd',\n       'file': 'https://your-host/<path_to_file>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd.part',\n       'filename': 'example.bin',\n       'offset': 10000,\n       `created_at`: '2021-05-18T17:12:50.318718Z',\n       'status': 1,\n       'completed_at': None,\n       'user': 1\n   }\n   ```\n\n3. Repeatedly PUT subsequent chunks to the `url` returned from the server.\n   Example:\n\n   ```python\n   # PUT to https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd\n   upload_url = \"https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd\"\n   r = requests.put(\n       upload_url,\n       headers={\n           \"Content-Range\": \"bytes {}-{}/{}\".format(index, index + size - 1, total),\n       },\n       data={\"filename\": build_file},\n       files={'file': chunk_data},\n   )\n   ```\n\n4. Server will continue responding with the `url` and current `offset`.\n5. Finally, when upload is completed, POST a request to the returned `url`.\n   This request must include the checksum (hex) of the entire file. Example:\n\n   ```python\n   # POST to https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd\n   upload_url = \"https://your-host/<path_to_view>/f64ebd67-83a3-45b6-8acd-c749ea1ed4cd\"\n   r = requests.post(upload_url, data={\"md5\": \"fc3ff98e8c6a0d3087d515c0473f8677\"})\n   ```\n\n6. If everything is OK, server will response with status code 200 and the data\n   returned in the method `get_response_data` (if any).\n\nIf you want to upload a file as a single chunk, this is also possible! Simply\nmake the first request a POST and include the checksum digest for the file. You\ndon't need to include the `Content-Range` header if uploading a whole file.\n\nIf you want to see the list of pending chunked uploads, make a `GET` request to\nthe URL linked to `ChunkedUploadView` (or any subclass). You will get a list of\npending chunked uploads (for the currently authenticated user only).\n\n**Possible error responses:**\n\n- Upload has expired. Server responds 410 (Gone).\n- `id` does not match any upload. Server responds 404 (Not found).\n- No chunk file is found in the indicated key. Server responds 400 (Bad\n  request).\n- Request does not contain `Content-Range` header. Server responds 400 (Bad\n  request).\n- Size of file exceeds limit (if specified). Server responds 400 (Bad request).\n- Offsets do not match. Server responds 400 (Bad request).\n- Checksums do not match. Server responds 400 (Bad request).\n\n## Settings\n\nAdd any of these variables into your project settings to override them.\n\n`DRF_CHUNKED_UPLOAD_EXPIRATION_DELTA`\n\n- How long after creation the upload will expire.\n- Default: `datetime.timedelta(days=1)`\n\n`DRF_CHUNKED_UPLOAD_PATH`\n\n- Path where uploaded files will be stored.\n- Default: `'chunked_uploads/%Y/%m/%d'`\n\n`DRF_CHUNKED_UPLOAD_CHECKSUM`\n\n- The type of checksum to use when verifying checksums. Options include\n  anything supported by Python\\'s hashlib (md5, sha1, sha256, etc)\n- Default: `'md5'`\n\n`DRF_CHUNKED_UPLOAD_COMPLETE_EXT`\n\n- Extension to use for completed uploads. Uploads will be renamed using this\n  extension on completion, unless this extension matched\n  `DRF_CHUNKED_UPLOAD_INCOMPLETE_EXT`.\n- Default: `'.done'`\n\n`DRF_CHUNKED_UPLOAD_INCOMPLETE_EXT`\n\n- Extension for in progress upload files.\n- Default: `'.part'`\n\n`DRF_CHUNKED_UPLOAD_STORAGE_CLASS`\n\n- Storage system (should be a class)\n- Default: `None` (use default storage system)\n\n`DRF_CHUNKED_UPLOAD_USER_RESTRICED`\n\n- Boolean that determines whether only the user who created an upload can\n  view/continue an upload.\n- Default: `True`\n\n`DRF_CHUNKED_UPLOAD_ABSTRACT_MODEL`\n\n- Boolean that defines if the `ChunkedUpload` model will be abstract or not\n  ([what does abstract model mean?][abstract-model]).\n- Default: `True`\n\n`DRF_CHUNKED_UPLOAD_MAX_BYTES`\n\n- Max amount of data (in bytes) that can be uploaded. `None` means no limit.\n- Default: `None`\n\n## Support\n\nIf you find any bug or you want to propose a new feature, please use the\n[issues tracker][issues]. Pull requests are accepted.\n\n[test-status-image]: https://github.com/jkeifer/drf-chunked-upload/actions/workflows/python-test.yml/badge.svg\n[test-status]: https://github.com/jkeifer/drf-chunked-upload/actions/workflows/python-test.yml\n[coverage-status-image]: https://img.shields.io/codecov/c/github/jkeifer/drf-chunked-upload/main.svg\n[codecov]: https://codecov.io/github/jkeifer/drf-chunked-upload?branch=main\n[pypi-version]: https://img.shields.io/pypi/v/drf-chunked-upload.svg\n[pypi]: https://pypi.org/project/drf-chunked-upload/\n[github-jm]: https://github.com/juliomalegria\n[dcu]: https://github.com/juliomalegria/django-chunked-upload\n[issues]: https://github.com/jkeifer/drf-chunked-upload/issues\n[lic]: https://romanrm.net/mit-zero\n[abstract-model]: https://docs.djangoproject.com/en/3.2/topics/db/models/#abstract-base-classes\n",
    "bugtrack_url": null,
    "license": "MIT-Zero",
    "summary": "Upload large files to Django REST Framework in multiple chunks, with the ability to resume if the upload is interrupted.",
    "version": "0.6.0",
    "project_urls": {
        "Homepage": "https://github.com/jkeifer/drf-chunked-upload"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6f7be21e2ae8921a1c0d2a6aafdaaa8cca59c7d46ca252ab385cd817a6135170",
                "md5": "ecf62c89e686b6c83960584ba385c6b5",
                "sha256": "addf414c973277856f23921fe5291aa1a4634331e45e00caf17c7778011d0626"
            },
            "downloads": -1,
            "filename": "drf_chunked_upload-0.6.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ecf62c89e686b6c83960584ba385c6b5",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">3.7",
            "size": 14088,
            "upload_time": "2023-08-13T02:54:35",
            "upload_time_iso_8601": "2023-08-13T02:54:35.234265Z",
            "url": "https://files.pythonhosted.org/packages/6f/7b/e21e2ae8921a1c0d2a6aafdaaa8cca59c7d46ca252ab385cd817a6135170/drf_chunked_upload-0.6.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "bbc75bfaf2cf519d0e7e8b476415ca7728db9fc10e993db15c016091559b45ff",
                "md5": "bed5235a17ecdb4cbbff6d2fa4307fb4",
                "sha256": "1832bd7899269165aa638d718b39c749b3cc45b65e15029614643853a8fefb54"
            },
            "downloads": -1,
            "filename": "drf-chunked-upload-0.6.0.tar.gz",
            "has_sig": false,
            "md5_digest": "bed5235a17ecdb4cbbff6d2fa4307fb4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">3.7",
            "size": 13492,
            "upload_time": "2023-08-13T02:54:36",
            "upload_time_iso_8601": "2023-08-13T02:54:36.743467Z",
            "url": "https://files.pythonhosted.org/packages/bb/c7/5bfaf2cf519d0e7e8b476415ca7728db9fc10e993db15c016091559b45ff/drf-chunked-upload-0.6.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-08-13 02:54:36",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "jkeifer",
    "github_project": "drf-chunked-upload",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "tox": true,
    "lcname": "drf-chunked-upload"
}
        
Elapsed time: 0.17710s