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.
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.
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()
If you want to upload multiple files using one form field, create a subclass
of the field’s widget and set its allow_multiple_selected
class attribute
to True
.
In order for such files to be all validated by your form (and have the value of
the field include them all), you will also have to subclass FileField
. See
below for an example.
Multiple file field
Django is likely to have a proper multiple file field support at some point in the future.
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()
Then override the form_valid()
method of your
FormView
subclass to handle multiple file
uploads:
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 form_valid(self, form):
files = form.cleaned_data["file_field"]
for f in files:
... # Do something with each file.
return super().form_valid(form)
Aviso
This will allow you to handle multiple files at the form level only. Be
aware that you cannot use it to put multiple files on a single model
instance (in a single field), for example, even if the custom widget is used
with a form field related to a model FileField
.
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.
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.
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.
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
...
abr. 23, 2025