Pular para o conteúdo
Ramos da Informática - Comunidade de Desenvolvedores

Torne-se um desenvolvedor FullStack: Pacote completo de formação desenvolvedor Frontend e Backend utilizando as linguagens de programação e frameworks mais procurados no mercado de trabalho. Mais informações, aqui. Faça o download do E-BookGuia Completo Para Se Tornar um(a) Desenvolvedor(a) Full-Stack, Começando do ZERO”.

Engenheiro de Software, autor de livros sobe tecnologia e negócios. É mantenedor do site Ramos da Informática. Hobbies: investir em ações, natação e finanças.

Engenheiro de Software, autor de livros sobe tecnologia e negócios. É mantenedor do site Ramos da Informática. Hobbies: investir em ações, natação e finanças.

admin

Todos os artigos deste autor

Upload de arquivos no Django: entendendo os modos de leitura

Chatbots com Whatsapp e Cielo integrados Nesse curso, eu vou te mostrar como o consumidor poder realizar um pagamento por dentro do aplicativo do WhatsApp, aonde o seu cliente vai entrar numa conversa como entraria numa conversa com qualquer pessoa ou com a sua empresa, navegar entre os produtos/serviços em menus simples enviados pelo chatbot, adicionar esses produtos/serviços no carrinho de compras, e num determinado ponto do chat, um link exclusivo é enviado para o cliente preencher os dados do cartão de crédito. No final, a análise é devolvida para o Whatsapp no qual a conversa foi iniciada. Inscreva-se.

Em uma conversa com a galera do Welcome to the Django acabei experimentando e aprendendo – na prática — sobre csv, strings, bytes, file object e a maneira como uploads funcionam. Registrei minha exploração e espero que mais gente possa encontrar uma ou outra coisa nova aqui!

O problema

Fui alterar um projeto feito com Django, atualizando do Python 2 para o Python 3, e me deparei com um pedaço de uma view que, como o Henrique Bastos falou, funcionava “por acaso” no Python 2:

def foobar(request):

lines = csv.reader(request.FILES[‘file.csv’])
for line in lines:

Essa view recebe um arquivo CSV (upload do usuáio) e só processa as linhas do arquivo, sem salvá-lo em disco. No Python 3, esse trecho da view passou a dar erro:

_csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)

O Henrique, além de falar que o código funcionava “por acaso”, me lembrou que o csv.reader(…) já recebe um arquivo aberto. Assim fui explorar a maneira que o Django estava me entregando os arquivos no HttpRequest (no caso da minha view, o que eu tinha em mãos no request.FILES[‘file.csv’]).

Simulando o ambiente da view

Para explorar isso, eu precisava simular o ambiente da minha view. Comecei criando um arquivo simples, teste.txt:

Linha 1, foo
Linha 2, bar
Linha 3, acentuação

Depois fui ler a documentação do HttpRequest.FILES e descobri que os arquivos ali disponíveis são instâncias de UploadedFile.

Logo, se eu criar uma instância da classe UploadedFile, posso acessar um objeto do mesmo tipo que eu acessava na view pelo request.FILES[‘file.csv’]. Para criar essa instância, preciso de um arquivo aberto, algo como open(file_path, modo). Para continuar a simulação, eu precisava saber de que forma o Django abre o arquivo do upload quando instancia ele no HttpRequest.FILES.

Eu desconfiava que não era em texto (r), que era em binário (rb). A documentação do curl, por exemplo, indicava que os arquivos eram enviados como binários. A documentação da Requests tem um aviso grande, em vermelho, desencorajando qualquer um usar outro modo que não o binário.

Lendo mais sobre o UploadedFile descobri que esse objeto tem um atributo file que, é uma referência ao file object nativo do Python que a classe UploadFile envolve. E esse atributo file, por sua vez, tem o atributo mode que me diz qual o modo foi utilizado na abertura do arquivo. Fui lá na minha view e dei um print(request.FILES[‘file.csv’].file.mode) e obtive rb como resposta.

Pronto! Finalmente eu tinha tudo para simular o ambiente da view no meu IPython:

import csv
from django.core.files.uploadedfile import UploadedFile
uploaded = UploadedFile(open(‘teste.txt’, ‘rb’), ‘teste.txt’)

Assim testei o trecho que dava problema…

for line in csv.reader(uploaded.file):
print(line)

… e obtive o mesmo erro.

Solução

Como já tinha ficado claro, o arquivo estava aberto como binário. Isso dá erro na hora de usar o csv.reader(…), pois o csv.reader(…) espera um texto, string como argumento. Aqui nem precisei ler a documentação, só lembrei da mensagem de erro: did you open the file in text mode? – ou seja, você abriu o arquivo no modo texto?

Lendo a documentação do UploadedFile e do File do Django (já que a primeira herda da segunda), achei dois métodos úteis: o close() e o open(). Com eles fechei o arquivo que estava aberto no modo rb e (re)abri o mesmo arquivo como r:

uploaded.close()
uploaded.open(‘r’)

Agora sim o arquivo está pronto para o csv.reader(…):

for line in csv.reader(uploaded.file):
print(line)
[‘Linha 1’, ‘ foo’]
[‘Linha 2’, ‘ bar’]
[‘Linha 3’, ‘ acentuação’]

Enfim, esse métodos UploadedFile.close() e UploadedFile.open(mode=mode) podem ser muito úteis quando queremos fazer algo diferente de gravar os arquivos recebidos em disco.

Quem aprendeu alguma coisa nova?

— Raymond Hettinger

Este artigo foi importado automaticamente por fazer parte do Planetário Dev. Quer fazer parte deste HUB de conteúdos? Faça parte do Planetário e veja as vantagens.

Não tem site ou blog? Seja um autor do site e ainda pode ser remunerado.

Leia também:

Facebook
LinkedIn
Twitter
Pinterest
Reddit
Telegram
WhatsApp
Email
Print

Relacionados

Deixe uma resposta