Skip to content

Monthly Archives: April 2008

Rumo ao fisl 9.0

16-Apr-08

Partindo de Curitiba as 17h com destino a Porto Alegre.

Para os que vão, nos vemos lá! :)

Forçando o download de arquivos com Django

08-Apr-08

Primeiro post pelo Planeta GNU/Linux Brasil. :)

Essa semana precisei criar uma aplicação web que disponibilizasse alguns arquivos para download e então decidi fazer isso utilizando Python e Django.

Uma parte da minha aplicação consistia em forçar o browser a abrir uma janela de download ao invés de exibir o arquivo (como acontece no caso de imagens ou arquivos texto). Eu já havia feito isso algumas vezes em PHP, mas fui pesquisar para ver se o Django não possuia alguma função pronta que me facilitasse essa tarefa, algo como:


return HttpResponseFile(file)

Passei algum tempo procurando por alguma solução mais inteligente do que alterar o header na mão, mas não consegui encontrar nada. Fui então atrás da documentação oficial, para descobrir como eu podia aplicar a solução que eu já utilizava em PHP para a realidade do Django. Encontrei aqui a “receita de bolo” de como alterar o header da requisição e fazer com que o browser agisse da forma como eu queria.

Portanto segue abaixo, a parte principal da minha implementação:

urls.py

Esse arquivo tem uma única função: extrair da url o nome do arquivo a ser baixado e passa-lo como parametro para a view.


urlpatterns = patterns('',
    (r'(?P<file>(^.*$)', 'myproject.apps.download.views.index'),
)

views.py

Aqui é onde a mágica ocorre… na verdade não é nada muito mágico, mas enfim. :)

Essa view apenas verifica se o arquivo existe e o envia para download, caso o arquivo não exista, retorna a página 404. Nessa função você pode aplicar várias outras validações, como verificar se o usuário está logado ou se ele relamente tem acesso a esse arquivo, etc. porém nada disso era necessário no meu caso.


from django.http import HttpResponse, Http404
from django.conf import settings
from os import path
import mimetypes

def index(request, file=''):
    abspath = path.join(settings.BASEPATH, 'your/path', file)
    if not (file and path.exists(abspath)):
        raise Http404()
    mimetype, encoding = mimetypes.guess_type(abspath)
    if mimetype is None:
        mimetype = 'application/force-download'
    response = HttpResponse(open(abspath, 'r').read())
    response['Content-Type'] = mimetype
    response['Pragma'] = 'public'
    response['Expires'] = '0'
    response['Cache-Control'] = 'must-revalidate, post-check=0, pre-check=0'
    response['Content-Disposition'] = 'attachment; filename=%s' % file
    response['Content-Transfer-Encoding'] = 'binary'
    response['Content-Length'] = str(path.getsize(abspath))
    return response

Espero que seja de alguma utilidade… e se alguém tiver uma solução melhor! Por favor, poste nos comentários.

Não faz muito tempo que eu mexo com Django, mas estou gostando da brincadeira!
Acredito que o número de posts sobre Python desse blog tende a crescer consideravelmente… e isso é bom!

UPDATE1: Depois de algum tempo com o sistema em produção, foi constatado que a solução acima não funciona em algumas versão do Internet Explorer 7. A solução do problema também foi documentada e está disponível aqui.

UPDATE2: Adicionada a sugestão de Alexander Benatti com relação a criação da variável abspath.