“Upload” de arquivosLink para este cabeçalho
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.
Básico sobre upload de arquivosLink para este cabeçalho
Consider a simple form containing a FileField:
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:
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.Link para este cabeçalho
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 arquivosLink para este cabeçalho
Se você quer enviar múltiplos arquivos usando um campo de modelo, defina o atributo HTML ``multiple``do “widget” do campo:
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:
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 arquivosLink para este cabeçalho
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 armazenadosLink para este cabeçalho
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 arquivosLink para este cabeçalho
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çãoLink para este cabeçalho
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)]