Desejo que os usuários no site possam baixar arquivos cujos caminhos estejam ocultos para que não possam ser baixados diretamente.
Por exemplo, eu gostaria que o URL fosse algo assim: http://example.com/download/?f=somefile.txt
E no servidor, eu sei que todos os arquivos para download residem na pasta /home/user/files/
.
Existe uma maneira de fazer o Django servir esse arquivo para download, em vez de tentar encontrar uma URL e exibir para exibi-la?
Respostas:
Para o "melhor dos dois mundos", você pode combinar a solução da S.Lott com o módulo xsendfile : o django gera o caminho para o arquivo (ou o próprio arquivo), mas o serviço de arquivo real é tratado pelo Apache / Lighttpd. Depois de configurar o mod_xsendfile, a integração com sua visualização exige algumas linhas de código:
Obviamente, isso só funcionará se você tiver controle sobre seu servidor ou se sua empresa de hospedagem já tiver configurado o mod_xsendfile.
EDITAR:
EDIT: Para
nginx
verificar isso , ele usa emX-Accel-Redirect
vez doapache
cabeçalho X-Sendfile.fonte
smart_str
ele não funcionará conforme o esperado, pois o módulo apache X-Sendfile não pode decodificar a cadeia codificada por smart_str. Assim, por exemplo, o arquivo "Örinää.mp3" não pode ser exibido. E se alguém omitir o smart_str, o próprio Django gera um erro de codificação ascii porque todos os cabeçalhos são codificados no formato ascii antes do envio. A única maneira que conheço para contornar esse problema é reduzir os nomes de arquivos X-sendfile para aqueles que consistem apenas em ascii.Um "download" é simplesmente uma alteração no cabeçalho HTTP.
Consulte http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment para saber como responder com um download .
Você só precisa de uma definição de URL
"/download"
.A solicitação
GET
ouPOST
dicionário terá as"f=somefile.txt"
informações.Sua função de visualização simplesmente mesclará o caminho base com o
f
valor " ", abrir o arquivo, criar e retornar um objeto de resposta. Deve ter menos de 12 linhas de código.fonte
filepath = filepath.replace('..', '').replace('/', '')
Para uma solução muito simples, mas não eficiente ou escalonável , você pode simplesmente usar a
serve
exibição django embutida . Isso é excelente para protótipos rápidos ou trabalhos pontuais, mas, como foi mencionado ao longo desta pergunta, você deve usar algo como apache ou nginx na produção.fonte
S.Lott tem a solução "boa" / simples e elo80ka tem a "melhor" / solução eficiente. Aqui está uma solução "melhor" / média - sem configuração do servidor, mas mais eficiente para arquivos grandes do que a correção ingênua:
http://djangosnippets.org/snippets/365/
Basicamente, o Django ainda lida com a veiculação do arquivo, mas não carrega tudo na memória de uma só vez. Isso permite que o servidor (lentamente) sirva um arquivo grande sem aumentar o uso de memória.
Novamente, o X-SendFile da S.Lott ainda é melhor para arquivos maiores. Mas se você não pode ou não quer se preocupar com isso, essa solução intermediária aumentará sua eficiência sem problemas.
fonte
django.core.servers.httpbase
módulo privado não documentado, que possui um grande sinal de alerta na parte superior do código " NÃO USE PARA USO DE PRODUÇÃO !!! ", que está no arquivo desde que foi criado . De qualquer forma, aFileWrapper
funcionalidade em que esse trecho se baseia foi removida no django 1.9.Tentei a solução @Rocketmonkeys, mas os arquivos baixados estavam sendo armazenados como * .bin e recebiam nomes aleatórios. Isso não está bem, é claro. Adicionar outra linha de @ elo80ka resolveu o problema.
Aqui está o código que estou usando agora:
Agora você pode armazenar arquivos em um diretório privado (não dentro de / media nem / public_html) e expô-los via django a certos usuários ou sob certas circunstâncias.
Espero que ajude.
Graças a @ elo80ka, @ S.Lott e @Rocketmonkeys pelas respostas, obtive a solução perfeita combinando todas elas =)
fonte
filename="%s"
no cabeçalho Disposição de Conteúdo, para evitar problemas com espaços nos nomes dos arquivos. Referências: nomes de arquivos com espaços são truncados durante o download . Como codificar o parâmetro filename do cabeçalho Content-Disposition no HTTP?FileWrapper(open(path.abspath(file_name), 'rb'))
FileWrapper
foi removido desde Django 1.9from wsgiref.util import FileWrapper
Apenas mencionando o objeto FileResponse disponível no Django 1.10
Edit: Acabei de encontrar minha própria resposta enquanto procurava uma maneira fácil de transmitir arquivos via Django, então aqui está um exemplo mais completo (para o futuro). Parte do princípio que o nome FileField é
imported_file
views.py
urls.py
fonte
Foi mencionado acima que o método mod_xsendfile não permite caracteres não ASCII nos nomes de arquivos.
Por esse motivo, tenho um patch disponível para mod_xsendfile que permitirá que qualquer arquivo seja enviado, desde que o nome seja codificado por URL e o cabeçalho adicional:
É enviado também.
http://ben.timby.com/?p=149
fonte
Tente: https://pypi.python.org/pypi/django-sendfile/
"Abstração para descarregar uploads de arquivos para o servidor web (por exemplo, Apache com mod_xsendfile) uma vez que o Django verifique as permissões, etc."
fonte
Você deve usar apis sendfile fornecidas por servidores populares como
apache
ounginx
em produção. Muitos anos eu estava usando a API sendfile desses servidores para proteger arquivos. Em seguida, criou um aplicativo django baseado em middleware simples para esse fim, adequado tanto para fins de desenvolvimento quanto de produção. Você pode acessar o código-fonte aqui .UPDATE: na nova versão, o
python
provedor usa django,FileResponse
se disponível, e também adiciona suporte para muitas implementações de servidor, desde lighthttp, caddy a hiawathaUso
fileprovider
aplicativo àsINSTALLED_APPS
configurações,fileprovider.middleware.FileProviderMiddleware
àsMIDDLEWARE_CLASSES
configuraçõesFILEPROVIDER_NAME
configurações paranginx
ouapache
em produção; por padrão, épython
para fins de desenvolvimento.nas visualizações de função ou baseada em classe, defina o
X-File
valor do cabeçalho de resposta como caminho absoluto para o arquivo. Por exemplo,django-fileprovider
incrementado de uma maneira que seu código precisará apenas de modificações mínimas.Configuração Nginx
Para proteger o arquivo do acesso direto, você pode definir a configuração como
Aqui
nginx
define um URL de localização que/files/
somente acessa internamente. Se você estiver usando a configuração acima, poderá definir o arquivo X como,Ao fazer isso com a configuração nginx, o arquivo será protegido e você também poderá controlar o arquivo do django
views
fonte
O Django recomenda que você use outro servidor para servir mídia estática (outro servidor rodando na mesma máquina está bom.) Eles recomendam o uso de servidores como o lighttp .
Isso é muito simples de configurar. Contudo. se 'somefile.txt' for gerado sob solicitação (o conteúdo é dinâmico), convém que o django o atenda.
Django Docs - Arquivos estáticos
fonte
fonte
Outro projeto para dar uma olhada: http://readthedocs.org/docs/django-private-files/en/latest/usage.html Parece promissor, mas ainda não testei.
Basicamente, o projeto abstrai a configuração mod_xsendfile e permite que você faça coisas como:
fonte
django-private-files
...Eu já enfrentei o mesmo problema mais de uma vez e, portanto, implementado usando o módulo xsendfile e os decoradores de exibição de autenticação da django-filelibrary . Sinta-se à vontade para usá-lo como inspiração para sua própria solução.
https://github.com/danielsokolowski/django-filelibrary
fonte
Fornecendo acesso protegido à pasta html estática usando https://github.com/johnsensible/django-sendfile : https://gist.github.com/iutinvg/9907731
fonte
Eu fiz um projeto sobre isso. Você pode ver o meu repositório no github:
https://github.com/nishant-boro/django-rest-framework-download-expert
Este módulo fornece uma maneira simples de servir arquivos para download no framework django rest usando o módulo Apache Xsendfile. Ele também possui um recurso adicional de veicular downloads apenas para usuários pertencentes a um grupo específico
fonte