Reusable Django app for resumable parallel chunked file uploads
Project description
Frago
Frago is a reusable Django app that provides a secure, resumable, and parallel chunked file upload system. It supports large file uploads with resumable support, duplicate chunk detection, checksum verification, and customizable signal hooks — ideal for drone videos, media applications, and IoT devices.
🚀 Features
- Parallel & resumable chunked uploads
- Upload tracking via database (start, end, size per chunk)
- Checksum verification (MD5 or other algorithms)
- Duplicate chunk detection
- Upload expiration support
- Extensible via Django signals
- Pluggable authentication (user/device/anonymous)
- Local file storage (pluggable)
📦 Installation
pip install frago
Add frago to your Django INSTALLED_APPS:
# settings.py
INSTALLED_APPS = [
...
"frago",
]
Finally, run the following commands to create and apply the migrations:
python manage.py makemigrations frago
python manage.py migrate
⚙️ Configuration (optional)
you can confic these in settings.py
#🧠 How the uploader identifies the upload session
CHUNKED_UPLOADER_IDENTIFIER_MODE = "user"
Options: "anonymous" (default), "user"
You can override get_identifier() for custom logic.
# 📂 Where uploaded chunks are stored temporarily
CHUNKED_UPLOADER_CHUNK_UPLOAD_PATH = "chunked_uploads/"
# 📂 Where final assembled files go
CHUNKED_UPLOADER_ASSEMBLED_PATH = "assembled_videos/"
# 🔐 Hash type for file integrity checks
CHUNKED_UPLOADER_CHECKSUM_TYPE = "md5"
Any hashlib-supported algorithm (e.g., "sha256")
# ✅ Whether to perform checksum verification
CHUNKED_UPLOADER_DO_CHECKSUM = True
# ⏱️ Chunk expiration time (used for cleanup jobs)
CHUNKED_UPLOADER_EXPIRATION = timedelta(days=1)
# 📦 Read buffer size during assembly
CHUNKED_UPLOADER_ASSEMBLE_READ_SIZE = 8 * 1024 * 1024 # 8MB
# 🧱 Custom chunk model path (if overriding)
CHUNKED_UPLOADER_CHUNK_MODEL = "frago.ChunkedUploadChunk"
# 🧩 Custom upload model path (if overriding)
CHUNKED_UPLOADER_UPLOAD_MODEL = "frago.ChunkUpload"
🧩 API Usage
1. Start a new upload
POST /upload/
Request:
{
"filename": "video.mp4",
"total_size": 104857600
}
Response:
{
"status": true,
"upload_id": "uuid4-string",
"message": "Upload started for video.mp4"
}
2. Upload a chunk
PUT /upload/{upload_id}/
Headers:
Content-Range: bytes 0-1048575/104857600
Body: multipart/form-data with key file and binary chunk data.
3. Finalize upload
POST /upload/{upload_id}/
Request
{
"checksum": "d41d8cd98f00b204e9800998ecf8427e",
"checksum_algo": "md5"
}
Response
{
"status": true,
"upload_id": "uuid4-string",
"message": "Upload completed for video.mp4"
}
4. Get upload status (only for authenticated users)
GET /upload/{upload_id}/
Or list uploads by current user/device:
GET /upload/
🧠 Models
ChunkUpload
Tracks a single upload:
upload_id: UUID
filename, total_size
status: in_progress, complete, expired
created_at, completed_at
ChunkedUploadChunk
Tracks individual uploaded chunks:
start, end, size
Foreign key to ChunkUpload
🧰 Signals
Frago emits the following Django signals:
Signal Triggered When
upload_started : New upload is created
chunk_received : A chunk is received and saved
upload_completed : All chunks assembled, upload finalized
checksum_failed : Checksum mismatch during finalization
To extend behavior, connect signal handlers:
from frago.signals import upload_started
def my_handler(sender, upload, **kwargs):
print("Upload started:", upload.filename)
upload_started.connect(my_handler)
🧪 Usage Example
Add to your urls.py (if you are using with out any overides):
path('api/',include('frago.urls')),
🧼 Cleanup:
Uploads expire after a period (EXPIRATION) and are marked expired.
Chunks and their metadata are deleted automatically on completion.
OVERIDING
This is an example how you can overide and set your custome logic
🔒 Custom Authentication Example
By default, the view allows anonymous access. You should subclass the view and add authentication:
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication
from frago.views import ParallelChunkedUploadView
class SecureUploadView(ParallelChunkedUploadView):
authentication_classes = [JWTAuthentication]
permission_classes = [IsAuthenticated]
🧠 Overriding the Identifier
class MyView(ParallelChunkedUploadView):
authentication_classes = [CustomAuthentication]
identifier_field = 'device'
def get_identifier(self, request):
if self.IDENTIFIER_MODE == 'device':
device_id = request.user
if not device_id:
raise PermissionDenied("Device ID not found.")
try:
device = Devices.objects.get(inventory_id=device_id)
print('device',device.id)
return device # or another unique identifier
except Devices.DoesNotExist:
raise PermissionDenied("Invalid Device ID.")
# fallback to parent logic
return super().get_identifier(request)
Update your urls.py:
urlpatterns = [
path('upload/',MyView.as_view()),
path('upload/<uuid:pk>/', MyView.as_view()),
]
🔧 Custom Upload Model Example
class Mychunkupload(AbstractChunkUpload):
device = models.ForeignKey(Devices,on_delete=models.CASCADE)
def assembled_path(self):
try:
device = Devices.objects.get(inventory_id=self.device_id)
base_path = device.videos or settings.ASSEMBLED_PATH
except Exception as e:
base_path = settings.ASSEMBLED_PATH
return os.path.join(base_path, f'{self.filename}')
Register it in settings:
CHUNKED_UPLOADER_UPLOAD_MODEL = 'fragotest.Mychunkupload'
and specify the identifier field in the view
identifier_field = 'device'
🔗 Uploader Client
Use the official uploader client:
👉 frago-client
📄 License
This project is licensed under the MIT License.
🤝 Contributing
Pull requests are welcome!
Please open an issue first to discuss your idea.
Make sure to add tests for any new features or logic changes.
🙌 Author
Built with ❤️ to support scalable file upload workflows in Django.
Let me know if you want:
Markdown preview badges
GitHub Actions/test coverage
Python client script (httpx/requests)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file frago-0.1.4.tar.gz.
File metadata
- Download URL: frago-0.1.4.tar.gz
- Upload date:
- Size: 14.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
327faee6b65a94c96ca5ec79a6c71f382c088012c10624c9dead82eb0f789b2c
|
|
| MD5 |
d9f0ab956d16af7a9703c6805bb7ee01
|
|
| BLAKE2b-256 |
83f03b4c58bb565b9b4323efe7629cbaf0d3322f4933a37f409df2fef9339a26
|
Provenance
The following attestation bundles were made for frago-0.1.4.tar.gz:
Publisher:
publish.yml on Albinm123/frago
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
frago-0.1.4.tar.gz -
Subject digest:
327faee6b65a94c96ca5ec79a6c71f382c088012c10624c9dead82eb0f789b2c - Sigstore transparency entry: 271545833
- Sigstore integration time:
-
Permalink:
Albinm123/frago@22f8d1f5cb7ddb38c7a9e2fe0ca3d2323d6dd421 -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/Albinm123
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@22f8d1f5cb7ddb38c7a9e2fe0ca3d2323d6dd421 -
Trigger Event:
release
-
Statement type:
File details
Details for the file frago-0.1.4-py3-none-any.whl.
File metadata
- Download URL: frago-0.1.4-py3-none-any.whl
- Upload date:
- Size: 13.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
967c9fca5686d057e4dd33501a15aa39bbe1a94a829786119275eb69cacadec1
|
|
| MD5 |
f82559c895ace92f151c477bc140f3e8
|
|
| BLAKE2b-256 |
4de943600c801afee8c7682d33bfa0d96a478b84002d2d71fc593d0fe500fd24
|
Provenance
The following attestation bundles were made for frago-0.1.4-py3-none-any.whl:
Publisher:
publish.yml on Albinm123/frago
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
frago-0.1.4-py3-none-any.whl -
Subject digest:
967c9fca5686d057e4dd33501a15aa39bbe1a94a829786119275eb69cacadec1 - Sigstore transparency entry: 271545837
- Sigstore integration time:
-
Permalink:
Albinm123/frago@22f8d1f5cb7ddb38c7a9e2fe0ca3d2323d6dd421 -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/Albinm123
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@22f8d1f5cb7ddb38c7a9e2fe0ca3d2323d6dd421 -
Trigger Event:
release
-
Statement type: