# documentação Django 2.0.8

# “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 simple 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 que `request.FILES` somente terá dados se o métodos de requisição for `POST` e o `<form>` que postou a requisição tem o atributo `enctype="multipart/form-data"`. Do contrário, o `request.FILES` estará vazio.

Na maioria das vezes, você simplesmente passa os dados do arquivo vindos do `request` para o formulário como descrito no Binding uploaded files to a form. Isso deve se parecer como:

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

Se você estiver construindo um objeto manualmente, você pode simplesmente assinalar o objeto arquivo vindo do `request.FILES` ao campo arquivo do modelo:

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

### 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 FileFieldView(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.

Essas especificações – 2.5 megabytes; `/tmp`; etc – são simplesmente “padrões razoáveis” que podem ser personalizadas como descrito na próxima seção.

### 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.

Se você quer trocar completamente os manipuladores de envio de arquivo, você pode apenas assinalar uma nova lista.

    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