# Django 6.0.5 documentation

# Filuppladdning

När Django hanterar en filuppladdning placeras filinformationen i `request.FILES` (för mer information om objektet `request` se dokumentationen för request and response objects). I det här dokumentet förklaras hur filer lagras på disk och i minne och hur du anpassar standardbeteendet.

Varning

Det finns säkerhetsrisker om du accepterar uppladdat innehåll från icke betrodda användare! Se säkerhetsguidens ämne om Innehåll som laddats upp av användare för mer information om begränsning.

## Grundläggande filuppladdningar

Tänk dig ett formulär som innehåller en `FileField`:

`forms.py`

    from django import forms

    class UploadFileForm(forms.Form):
        title = forms.CharField(max_length=50)
        file = forms.FileField()

En vy som hanterar detta formulär kommer att få filinformationen i `request.FILES`, som är en ordbok som innehåller en nyckel för varje `FileField` (eller `ImageField`, eller annan `FileField` subklass) i formuläret. Så data från ovanstående formulär skulle vara tillgängliga som `request.FILES['file']`.

Observera att `request.FILES <django.http.HttpRequest.FILES>`` endast kommer att innehålla data om förfrågningsmetoden var `POST`, minst ett filfält faktiskt postades och `<form>` som postade förfrågan har attributet `enctype="multipart/form-data"`. Annars kommer `request.FILES` att vara tomt.

För det mesta kommer du att skicka filinformationen från `request` till formuläret enligt beskrivningen i Binder uppladdade filer till ett formulär. Detta skulle se ut ungefär som:

`Vyer.py`

    from django.http import HttpResponseRedirect
    from django.shortcuts import render
    from .forms import UploadFileForm

    # Imaginary function to handle an uploaded file.
    from somewhere import handle_uploaded_file

    def upload_file(request):
        if request.method == "POST":
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                handle_uploaded_file(request.FILES["file"])
                return HttpResponseRedirect("/success/url/")
        else:
            form = UploadFileForm()
        return render(request, "upload.html", {"form": form})

Observera att vi måste skicka `request.FILES` till formulärets konstruktör; det är så här fildata binds till ett formulär.

Här är ett vanligt sätt att hantera en uppladdad fil:

    def handle_uploaded_file(f):
        with open("some/file/name.txt", "wb+") as destination:
            for chunk in f.chunks():
                destination.write(chunk)

Genom att loopa över `UploadedFile.chunks()` istället för att använda `read()` säkerställs att stora filer inte överbelastar systemets minne.

Det finns några andra metoder och attribut som är tillgängliga för `UploadedFile`-objekt; se `UploadedFile` för en fullständig referens.

### Hantera uppladdade filer med en modell

Om du sparar en fil på en `Model` med en `FileField`, kan du använda en `ModelForm` som gör processen mycket enklare. Filobjektet kommer att sparas på den plats som anges av `upload_to`-argumentet för motsvarande `FileField` när du anropar `form.save()`:

    from django.http import HttpResponseRedirect
    from django.shortcuts import render
    from .forms import ModelFormWithFileField

    def upload_file(request):
        if request.method == "POST":
            form = ModelFormWithFileField(request.POST, request.FILES)
            if form.is_valid():
                # file is saved
                form.save()
                return HttpResponseRedirect("/success/url/")
        else:
            form = ModelFormWithFileField()
        return render(request, "upload.html", {"form": form})

Om du konstruerar ett objekt manuellt kan du tilldela filobjektet från `request.FILES` till filfältet i modellen:

    from django.http import HttpResponseRedirect
    from django.shortcuts import render
    from .forms import UploadFileForm
    from .models import ModelWithFileField

    def upload_file(request):
        if request.method == "POST":
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                instance = ModelWithFileField(file_field=request.FILES["file"])
                instance.save()
                return HttpResponseRedirect("/success/url/")
        else:
            form = UploadFileForm()
        return render(request, "upload.html", {"form": form})

Om du konstruerar ett objekt manuellt utanför en begäran kan du tilldela ett `File` liknande objekt till `FileField`:

    from django.core.management.base import BaseCommand
    from django.core.files.base import ContentFile

    class MyCommand(BaseCommand):
        def handle(self, *args, **options):
            content_file = ContentFile(b"Hello world!", name="hello-world.txt")
            instance = ModelWithFileField(file_field=content_file)
            instance.save()

### Ladda upp flera filer

Om du vill ladda upp flera filer med ett formulärfält skapar du en underklass av fältets widget och ställer in klassattributet `allow_multiple_selected` på `True`.

För att alla sådana filer ska kunna valideras av ditt formulär (och fältets värde ska inkludera dem alla) måste du också underklassa `FileField`. Se nedan för ett exempel.

Fält för flera filer

Django kommer sannolikt att ha ett ordentligt stöd för flera filfält någon gång i framtiden.

`forms.py`

    from django import forms

    class MultipleFileInput(forms.ClearableFileInput):
        allow_multiple_selected = True

    class MultipleFileField(forms.FileField):
        def __init__(self, *args, **kwargs):
            kwargs.setdefault("widget", MultipleFileInput())
            super().__init__(*args, **kwargs)

        def clean(self, data, initial=None):
            single_file_clean = super().clean
            if isinstance(data, (list, tuple)):
                result = [single_file_clean(d, initial) for d in data]
            else:
                result = [single_file_clean(data, initial)]
            return result

    class FileFieldForm(forms.Form):
        file_field = MultipleFileField()

Åsidosätt sedan metoden `form_valid()` i din `FormView`-underklass för att hantera flera filuppladdningar:

`Vyer.py`

    from django.views.generic.edit import FormView
    from .forms import FileFieldForm

    class FileFieldFormView(FormView):
        form_class = FileFieldForm
        template_name = "upload.html"  # Replace with your template.
        success_url = "..."  # Replace with your URL or reverse().

        def form_valid(self, form):
            files = form.cleaned_data["file_field"]
            for f in files:
                ...  # Do something with each file.
            return super().form_valid(form)

Varning

Detta gör att du kan hantera flera filer endast på formulärnivå. Tänk på att du inte kan använda den för att lägga till flera filer på en enda modellinstans (i ett enda fält), till exempel även om den anpassade widgeten används med ett formulärfält som är relaterat till en modell `FileField`.

## Uppladdningshanterare

När en användare laddar upp en fil skickar Django filinformationen till en uppladdningshanterare - en liten klass som hanterar filinformationen när den laddas upp. Uppladdningshanterare definieras initialt i inställningen `FILE_UPLOAD_HANDLERS`, som har standardvärdet:

    [
        "django.core.files.uploadhandler.MemoryFileUploadHandler",
        "django.core.files.uploadhandler.TemporaryFileUploadHandler",
    ]

Tillsammans tillhandahåller `MemoryFileUploadHandler` och `TemporaryFileUploadHandler` Djangos standardbeteende för filuppladdning genom att läsa små filer i minnet och stora filer på disken.

Du kan skriva egna handlers som anpassar hur Django hanterar filer. Du kan till exempel använda anpassade hanterare för att genomdriva kvoter på användarnivå, komprimera data i farten, rendera förloppsbalkar och till och med skicka data till en annan lagringsplats direkt utan att lagra dem lokalt. Se Skriva anpassade uppladdningshanterare för detaljer om hur du kan anpassa eller helt ersätta uppladdningsbeteendet.

### Var uppladdade data lagras

Innan du sparar uppladdade filer måste data lagras någonstans.

Som standard, om en uppladdad fil är mindre än 2,5 megabyte, kommer Django att hålla hela innehållet i uppladdningen i minnet. Det innebär att när filen sparas sker endast en läsning från minnet och en skrivning till disken och det går därför mycket snabbt.

Men om en uppladdad fil är för stor kommer Django att skriva den uppladdade filen till en temporär fil som lagras i ditt systems temporära katalog. På en Unix-liknande plattform betyder det att du kan förvänta dig att Django genererar en fil som heter något i stil med `/tmp/tmpzfp6I6.upload`. Om en uppladdning är tillräckligt stor kan du se den här filen växa i storlek när Django strömmar data till disken.

Dessa specifikationer – 2,5 megabyte; `/tmp`; etc. – är ”rimliga standardvärden” som kan anpassas enligt beskrivningen i nästa avsnitt.

### Ändra beteende för uppladdningshanterare

Det finns några inställningar som styr Djangos filuppladdningsbeteende. Se Filuppladdningsinställningar för detaljer.

### Ändra uppladdningshanterare i farten

Ibland kräver särskilda vyer olika uppladdningsbeteende. I dessa fall kan du åsidosätta uppladdningshanterare per begäran genom att ändra `request.upload_handlers`. Som standard innehåller den här listan de uppladdningshanterare som anges av `FILE_UPLOAD_HANDLERS`, men du kan ändra listan som du skulle göra med vilken annan lista som helst.

Anta till exempel att du har skrivit en `ProgressBarUploadHandler` som ger feedback om uppladdningsförloppet till någon form av AJAX-widget. Du skulle lägga till den här hanteraren till dina uppladdningshanterare så här:

    request.upload_handlers.insert(0, ProgressBarUploadHandler(request))

Genom att använda `list.insert()`, som visas ovan, säkerställs att förloppsindikatorn placeras i början av listan. Eftersom uppladdningshanterare exekveras i ordning garanterar denna placering att förloppsindikatorn körs före standardhanterarna, vilket gör att den kan spåra förloppet under hela uppladdningen.

Om du vill ersätta uppladdningshanterarna helt och hållet kan du tilldela en ny lista:

    request.upload_handlers = [ProgressBarUploadHandler(request)]

Observera

Du kan bara ändra uppladdningshanterare före åtkomst till `request.POST` eller `request.FILES` - det är inte meningsfullt att ändra uppladdningshanterare efter att uppladdningshanteringen redan har börjat. Om du försöker ändra `request.upload_handlers` efter att ha läst från `request.POST` eller `request.FILES` kommer Django att ge ett felmeddelande.

Därför bör du alltid modifiera uppladdningshanterare så tidigt som möjligt i din vy.

Also, `request.POST` is accessed by `CsrfViewMiddleware` which is enabled by default. This means you will need to use `csrf_exempt()` on your view to allow you to change the upload handlers. You will then need to use `csrf_protect()` on the function that actually processes the request. Note that this means that the handlers may start receiving the file upload before the CSRF checks have been done. Example code:

    from django.views.decorators.csrf import csrf_exempt, csrf_protect

    @csrf_exempt
    def upload_file_view(request):
        request.upload_handlers.insert(0, ProgressBarUploadHandler(request))
        return _upload_file_view(request)

    @csrf_protect
    def _upload_file_view(request):
        # Process request
        ...

Om du använder en klassbaserad vy måste du använda `csrf_exempt()` på dess `dispatch()` metod och `csrf_protect()` på den metod som faktiskt behandlar förfrågan. Exempel på kod:

    from django.utils.decorators import method_decorator
    from django.views import View
    from django.views.decorators.csrf import csrf_exempt, csrf_protect

    @method_decorator(csrf_exempt, name="dispatch")
    class UploadFileView(View):
        def setup(self, request, *args, **kwargs):
            request.upload_handlers.insert(0, ProgressBarUploadHandler(request))
            super().setup(request, *args, **kwargs)

        @method_decorator(csrf_protect)
        def post(self, request, *args, **kwargs):
            # Process request
            ...