File Uploads ¶
Datastar handles file uploads by encoding them as Base64 and sending them as part of your signals.
1. The Frontend ¶
Bind your file input to a signal. Datastar automatically converts the files into a list of objects.
async def home(c: Context, w: Writer):
w.html(
Div(
data.signals({"my_files": []}),
Input({"type": "file", "multiple": True}, data.bind("my_files")),
Button(data.on("click", at.post("/upload")), "Upload")
)
)
2. The Backend ¶
On the server, decode the Base64 data and save the file.
import base64
async def handle_upload(c: Context, w: Writer):
signals = await c.signals()
files = signals.get("my_files", [])
for file in files:
name = file["name"]
content_b64 = file["contents"] # Format: "data:image/png;base64,..."
# Strip the header
if "," in content_b64:
content_b64 = content_b64.split(",", 1)[1]
binary_data = base64.b64decode(content_b64)
with open(f"./uploads/{name}", "wb") as f:
f.write(binary_data)
w.sync({"my_files": []}) # Clear input on client
Important Notes ¶
- File Size: Base64 encoding increases file size by ~33%. For very large files (GBs), consider a direct multipart form upload or a pre-signed S3 URL.
- Structure: Each file object in the signal contains:
name: Filenamecontents: Base64 stringmime: MIME type (e.g.,image/png)
- Security: Always sanitize filenames before saving them to disk to prevent path traversal attacks.
