# documentação Django 4.0.8.dev20220803071047

# “Upload” de arquivos

Quando o Django lida com o upload de arquivos, o arquivo de dados termina sendo colocado em `request.FILES` (para mais sobre o objeto `request` veja a documentação sobre objetos de requisição e resposta). Este documento explica como arquivos são armazenados no disco ou na memória, e como personalizar o comportamento padrão.

Aviso

Existem riscos de segurança se você estiver aceitando o upload de conteúdo de usuários não confiáveis! Veja o tópico do guia de segurança em Conteúdo carregado por upload de usuários para detalhes.

## Básico sobre upload de arquivos

Consider a form containing a `FileField`:

`forms.py`

    from django import forms

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

Uma “view” que lida com este formulário irá receber o arquivo em `request.FILES`, o qual é um dicionário contendo uma chave para cada `FileField` (ou `ImageField`, ou outra subclasse de `FileField`) no formulário. Tal que os dados vindos do formulário acima devem estar acessíveis como `request.FILES['file']`.

Note that `request.FILES` will only contain data if the request method was `POST`, at least one file field was actually posted, and the `<form>` that posted the request has the attribute `enctype="multipart/form-data"`. Otherwise, `request.FILES` will be empty.

Most of the time, you’ll pass the file data from `request` into the form as described in Binding uploaded files to a form. This would look something like:

`views.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})

Note que temos que passar `request.FILES` para o construtor do “form”; é assim que os dados do arquivo entra no form.

Aqui uma maneira comum que você talvez lide com o “upload” de arquivo:

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

Fazendo “loops” sobre `UploadedFile.chunks()` ao invés de usar o `read()` garante que grandes arquivos não vão forçar a memória do seu sistema.

Existem alguns outros métodos e atributos disponíveis nos objetos `UploadedFile`; veja a `UploadedFile` para uma completa referência.

### Lindando com o “upload” de arquivos com um modelo.

Se você está usando um arquivo em uma `Model` com uma `FileField`, usando uma `ModelForm` faz este processo bem mais fácil. O objeto arquivo será salvo em um local especificado pelo argumento `upload_to` do `FileField` correspondente quando chamar `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})

If you are constructing an object manually, you can assign the file object from `request.FILES` to the file field in the model:

    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})

If you are constructing an object manually outside of a request, you can assign a `File` like object to the `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()

### Enviando múltiplos arquivos

Se você quer enviar múltiplos arquivos usando um campo de modelo, defina o atributo HTML ``multiple``do “widget” do campo:

`forms.py`

    from django import forms

    class FileFieldForm(forms.Form):
        file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

E então sobreescreva o método `post` da sua subclasse de `FormView` para manipular o envio de múltiplos arquivos:

`views.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 post(self, request, *args, **kwargs):
            form_class = self.get_form_class()
            form = self.get_form(form_class)
            files = request.FILES.getlist('file_field')
            if form.is_valid():
                for f in files:
                    ...  # Do something with each file.
                return self.form_valid(form)
            else:
                return self.form_invalid(form)

## Manipuladores de envios de arquivos

Quando um usuário envia um arquivo, o Django passa os dados do arquivo para um * manipular de envio de arquivo* – uma pequena classe que lida com dados de arquivos enquanto este é enviado. Manipuladores de envio de arquivo não inicialmente definidos na definição `FILE_UPLOAD_HANDLERS` o qual tem como padrão:

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

Juntos as classes class:MemoryFileUploadHandler e `TemporaryFileUploadHandler` fornecem ao Django um comportamento padrão para o envio de arquivos que lê arquios pequenos na memória e grandes arquivos no disco.

Você pode escrever manipuladores que personalizem a maneira como Django lida com arquivos. Você pode por exemplo, usar manipuladores personalizados para forçar quotas no nível do usuário, comprimir dados enquanto chegam, renderizar barras de progresso, e mesmo enviar dados diretamente para um outro local de armazenamento sem armazenar localmente. Para maiores detalhes veja o Writing custom upload handlers para saber como você pode personalizar ou mudar completamente o comportamento do envio.

### Onde os dados de arquivos enviados são armazenados

Antes que você salve os arquivos enviados, os dados precisam ser salvos em algum lugar.

Por padrão, se um arquivo enviado é menor que 2.5 megabytes, o Django irá manter todo o conteúdo do arquivo em memória. Isso significa que salvar o arquivo envolve somente uma leitura na memória e uma escrita no disco e portanto muito rápido.

Porém, se o arquivo enviado é muito grande, o Django irá escrever o arquivo enviado em um arquivo temporário no diretório de arquivos temporários do seu sistema. Em uma plataforma Unix isso significa que você pode esperar que o Django crie um arquivo cujo o nome seja algo como /tmp/tmpzfp6I6.upload`. Se o arquivo enviado é grande o bastante, você pode assistir o arquivo crescer em tamanho enquanto o Django transmite o dado para o disco.

These specifics – 2.5 megabytes; `/tmp`; etc. – are “reasonable defaults” which can be customized as described in the next section.

### Mudando o comportamento do manipulador de envio de arquivos

Existem algumas definições que controla como o manipulador de envio de arquivo do Django se comporta. Para detalhes veja o Definições de envio de arquivos.

### Modificando manipuladores de envio de arquivos durante a execução

As vezes uma “view” em particular requer um comportamento diferente para o envio de arquivos. Neste caso, você pode sobrescrever um manipulador baseado no “request” modificando o `request.upload_handlers`. Por padrão, esta lista contém os manipuladores informados pelo `FILE_UPLOAD_HANDLERS`, mas você pode modificar essa lista como qualquer outra lista.

Por exemplo, suponha que você tenha escrito um `ProgressBarUploadHandler` que dá um retorno sobre o progresso do envio do arquivo para algum tipo de “widget” AJAX. Você adicionaria este manipulador a sua lista de manipuladores como aqui:

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

Você provavelmente poderia querer usar o `list.insert()` neste caso (no lugar de `append()`) porque o manipulador de barra de progresso precisa rodar antes de qualquer outro. Lembre-se, os manipuladores de envio de arquivo são processados na ordem.

If you want to replace the upload handlers completely, you can assign a new list:

    request.upload_handlers = [ProgressBarUploadHandler(request)]

Nota

Você só pode modificar manipuladores de envio antes de acessar `request.POST` ou `request.FILES`– não faz sentido mudar o manipulador de arquivos depois que o tratamento do envio já iniciou. Se você tentar modificar o `request.upload_handlers` depois da leitura do ``request.POST``ou ``request.FILES``o Django irá emitir um erro.

Então, você deve sempre modificar os manipuladores de arquivos tão cedo quanto possível nas suas “views”.

Além disso, o `request.POST` é acessado pela `CsrfViewMiddleware` a qual está habilitada por padrão. Isso significa que você precisa usar o `csrf_exempt()` na sua “view”para que seja possível mudar os manipuladores de arquivos. Você precisará então do `csrf_protect()` na função que realmente processa a requisição. Note que isso significa que o manipulador de envio do arquivo começa a receber o arquivo antes que as verificações de CSRF sejam feitas. Exemplo de código:

    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

If you are using a class-based view, you will need to use `csrf_exempt()` on its `dispatch()` method and `csrf_protect()` on the method that actually processes the request. Example code:

    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