microdot.multipart — parsowanie multipart/form-data

Parsuje treści żądań Content-Type: multipart/form-data – kodowanie, którego przeglądarki używają dla formularzy zawierających pola <input type="file">. Dwie odmiany API:

  • Strumieniowy FormDataIter, który zwraca pola jedno po drugim – przydatny, gdy aplikacja musi obsługiwać bardzo duże przesyłane pliki kawałek po kawałku na urządzeniu o ograniczonej pamięci.

  • Dekorator with_form_data(), który buforuje wszystko i wypełnia request.form / request.files – wygodne API dla przesyłanych plików o normalnym rozmiarze.

class FormDataIter

class microdot.multipart.FormDataIter(request)

Asynchroniczny iterator po częściach treści multipart żądania request. Zwracanymi wartościami są krotki (name, value); value jest typu str dla zwykłych pól oraz FileUpload dla pól plików.

Używany bezpośrednio, gdy pamięć ma większe znaczenie niż wygoda:

from microdot.multipart import FormDataIter, FileUpload

@app.post('/upload')
async def upload(request):
    async for name, value in FormDataIter(request):
        if isinstance(value, FileUpload):
            await value.save('/sdcard/' + value.filename)
        else:
            print(name, '=', value)
    return 'ok'

Informacja

Podczas iterowania po polach plików plik musi zostać skonsumowany (za pomocą FileUpload.read() lub FileUpload.save()) przed następną iteracją async for – bazowy strumień jest unieważniany w momencie postępu iteracji.

buffer_size: int

Atrybut klasy. Rozmiar fragmentu używany podczas odczytu ze strumienia żądania. Domyślnie 256 bajtów. Zwiększ dla wyższej przepustowości kosztem pamięci RAM.

class FileUpload

class microdot.multipart.FileUpload(filename: str, content_type: str | None, read)

Pojedynczy przesłany plik. Instancje są zwracane przez FormDataIter i gromadzone w request.files przez with_form_data(). Aplikacje zwykle nie konstruują FileUpload bezpośrednio.

filename: str

Oryginalna nazwa pliku w postaci, w jakiej wysłał ją klient (niezaufana – nie przekazuj do open() bez oczyszczenia).

content_type: str | None

Typ MIME z nagłówka Content-Type części lub None, jeśli nie został podany.

max_memory_size: int

Atrybut klasy. Próg (w bajtach), powyżej którego copy() przełącza się z buforowania w pamięci na plik tymczasowy. Domyślnie 1024.

async read(n: int = -1)

Odczytuje do n bajtów ze strumienia przesyłania. -1 odczytuje do końca.

async save(path_or_file)

Zapisuje przesłany plik do path_or_file, którym może być ścieżka w systemie plików lub już otwarty obiekt pliku.

async copy(max_memory_size: int | None = None)

Buforuje przesłany plik (w pamięci RAM lub w pliku tymczasowym, w zależności od max_memory_size), aby reszta treści multipart mogła zostać sparsowana bez unieważnienia oryginalnego strumienia. Dekorator with_form_data() wywołuje to automatycznie.

async close()

Zwalnia wszelkie pliki tymczasowe utworzone przez copy(). Wywoływane automatycznie po zakończeniu żądania, jeśli przesłany plik dotarł do request.files za pośrednictwem with_form_data().

Dekoratory na poziomie modułu

microdot.multipart.with_form_data(f)

Dekorator, który parsuje treść multipart z wyprzedzeniem i wypełnia request.form oraz request.files przed uruchomieniem procedury obsługi:

from microdot import Microdot
from microdot.multipart import with_form_data

app = Microdot()

@app.post('/upload')
@with_form_data
async def upload(request):
    print('fields:', dict(request.form))
    for name, file in request.files.items():
        await file.save('/sdcard/' + sanitize(file.filename))
    return 'ok'

Przesyłane pliki są buforowane za pomocą FileUpload.copy(), więc procedura obsługi może swobodnie iterować po request.files i request.form. Pliki tymczasowe są czyszczone automatycznie po zakończeniu żądania.

Dla przesyłanych plików większych niż kilka megabajtów preferuj strumieniowe API FormDataIter; with_form_data() gromadzi całe żądanie w pamięci lub w systemie plików przed uruchomieniem procedury obsługi.