UploadMixin — drag & drop in 6 lines

Drop an image (jpg/png/gif/webp ≤ 5 MB) below. The default writer buffers to bytes, so this demo runs without any cloud storage configured.

Drop zone

UploadMixin

Drag & drop an image here

…or click to choose a file

The whole pattern

from djust.uploads import UploadMixin

class AvatarView(UploadMixin, LiveView):
    def mount(self, request, **kwargs):
        self.allow_upload(
            'avatar',
            accept='image/*',
            max_file_size=5_000_000,
            max_entries=1,
        )

    @event_handler()
    def save_avatar(self, **kwargs):
        for entry in self.consume_uploaded_entries('avatar'):
            # entry.client_name, entry.client_type, entry.data, entry.file
            avatar_path = save_to_disk(entry.data, entry.client_name)
            request.user.avatar = avatar_path
            request.user.save()

self.allow_upload(name, accept, max_file_size, max_entries) in mount(). <input type="file" dj-upload="name"> in the template. self.consume_uploaded_entries(name) in your handler to drain completed uploads.

For S3 / GCS / Azure direct-upload (pre-signed URLs, resumable across disconnects), subclass BufferedUploadWriter and pass it via writer=. Tracked at #26.

Bonus: {% skeleton %} shimmer placeholders

closes #9

Drop in {% skeleton skeleton_type="..." lines=N %} wherever you'd want to show a loading state. djust-components ships four variants:

type=text, lines=3
type=card
type=avatar
type=table, lines=4

Pair this with {% if loading %} (or assign_async's .loading flag — see the suspense demo) so the skeleton appears while data is in flight, then swaps to real content on resolution.