Django가 다운로드 가능한 파일을 제공하게 함
사이트의 사용자가 경로가 가려진 파일을 다운로드하여 직접 다운로드 할 수 없도록하고 싶습니다.
예를 들어 URL은 " http://example.com/download/?f=somefile.txt
그리고 서버에서 다운로드 가능한 모든 파일이 "/ home / user / files /"폴더에 있다는 것을 알고 있습니다.
Django가 URL을 찾고 표시하려고 시도하는 대신 파일을 다운로드하도록 제공하는 방법이 있습니까?
"두 세계의 최고"를 위해 S.Lott의 솔루션을 xsendfile 모듈 과 결합 할 수 있습니다 . django는 파일 (또는 파일 자체)의 경로를 생성하지만 실제 파일 제공은 Apache / Lighttpd에 의해 처리됩니다. mod_xsendfile을 설정하면 뷰와 통합하는 데 몇 줄의 코드가 필요합니다.
from django.utils.encoding import smart_str
response = HttpResponse(mimetype='application/force-download') # mimetype is replaced by content_type for django 1.7
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(path_to_file)
# It's usually a good idea to set the 'Content-Length' header too.
# You can also set any other required headers: Cache-Control, etc.
return response
물론 이것은 서버를 제어하거나 호스팅 회사가 이미 mod_xsendfile을 설정 한 경우에만 작동합니다.
편집하다:
django 1.7에서는 mimetype이 content_type으로 바뀝니다.
response = HttpResponse(content_type='application/force-download'
편집 : 들어 nginx확인 이 그것을 사용하는 X-Accel-Redirect대신 apacheX-sendfile을 헤더.
"다운로드"는 단순히 HTTP 헤더 변경입니다.
다운로드로 응답하는 방법 은 http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment 를 참조 하십시오. .
에 대한 하나의 URL 정의 만 필요합니다 "/download".
요청 GET또는 POST사전에 "f=somefile.txt"정보가 있습니다.
뷰 함수는 단순히 기본 경로를 " f"값 과 병합 하고 파일을 열고 응답 객체를 만들고 반환합니다. 코드는 12 줄 미만이어야합니다.
매우 간단 하지만 효율적이지 않거나 확장 가능하지 않은 솔루션의 경우 내장 장고 serve보기를 사용할 수 있습니다. 이것은 빠른 프로토 타입이나 일회성 작업에는 탁월하지만이 질문에서 언급했듯이 프로덕션에서는 아파치 나 nginx와 같은 것을 사용해야합니다.
from django.views.static import serve
filepath = '/some/path/to/local/file.txt'
return serve(request, os.path.basename(filepath), os.path.dirname(filepath))
S.Lott는 "양호한"/ 간단한 솔루션을, elo80ka는 "최고"/ 효율적인 솔루션을 제공합니다. 다음은 "더 나은"/ 중간 솔루션입니다. 서버 설정은 없지만 순진한 수정보다 큰 파일에 더 효율적입니다.
http://djangosnippets.org/snippets/365/
기본적으로 Django는 여전히 파일 서비스를 처리하지만 한 번에 모든 것을 메모리에로드하지 않습니다. 이를 통해 서버는 메모리 사용량을 늘리지 않고 (느리게) 큰 파일을 제공 할 수 있습니다.
다시 말하지만 S.Lott의 X-SendFile은 더 큰 파일에 더 좋습니다. 그러나 당신이 그것을 귀찮게하고 싶지 않다면,이 중간 솔루션은 번거 로움없이 더 나은 효율성을 얻을 것입니다.
@Rocketmonkeys 솔루션을 시도했지만 다운로드 한 파일이 * .bin으로 저장되고 임의의 이름이 지정되었습니다. 물론 좋지 않습니다. @ elo80ka에서 다른 줄을 추가하면 문제가 해결되었습니다.
다음은 현재 사용중인 코드입니다.
from wsgiref.util import FileWrapper
from django.http import HttpResponse
filename = "/home/stackoverflow-addict/private-folder(not-porn)/image.jpg"
wrapper = FileWrapper(file(filename))
response = HttpResponse(wrapper, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(filename)
response['Content-Length'] = os.path.getsize(filename)
return response
이제 / media 나 / public_html이 아닌 개인 디렉토리에 파일을 저장하고 django를 통해 특정 사용자 또는 특정 상황에 노출시킬 수 있습니다.
도움이 되길 바랍니다.
@ elo80ka, @ S.Lott 및 @Rocketmonkeys 덕분에 답변에 대한 완벽한 솔루션을 얻었습니다 =)
Django 1.10에서 사용 가능한 FileResponse 객체를 언급하면
편집 : Django를 통해 파일을 스트리밍하는 쉬운 방법을 검색하는 동안 내 대답에 부딪 쳤으므로 여기에 더 완벽한 예가 있습니다. FileField 이름이imported_file
views.py
from django.views.generic.detail import DetailView
from django.http import FileResponse
class BaseFileDownloadView(DetailView):
def get(self, request, *args, **kwargs):
filename=self.kwargs.get('filename', None)
if filename is None:
raise ValueError("Found empty filename")
some_file = self.model.objects.get(imported_file=filename)
response = FileResponse(some_file.imported_file, content_type="text/csv")
# https://docs.djangoproject.com/en/1.11/howto/outputting-csv/#streaming-large-csv-files
response['Content-Disposition'] = 'attachment; filename="%s"'%filename
return response
class SomeFileDownloadView(BaseFileDownloadView):
model = SomeModel
urls.py
...
url(r'^somefile/(?P<filename>[-\w_\\-\\.]+)$', views.SomeFileDownloadView.as_view(), name='somefile-download'),
...
위에서 mod_xsendfile 메소드는 파일 이름에 ASCII가 아닌 문자를 허용하지 않습니다.
이러한 이유로 이름이 URL로 인코딩되고 추가 헤더가있는 한 모든 파일을 보낼 수있는 mod_xsendfile에 사용할 수있는 패치가 있습니다.
X-SendFile-Encoding: url
전송됩니다.
시도 : https://pypi.python.org/pypi/django-sendfile/
"Django가 권한 등을 확인한 후 파일 업로드를 웹 서버 (예 : mod_xsendfile을 사용하는 Apache)로 오프로드하는 데 대한 관심
프로덕션 과 같이 apache또는 nginx프로덕션 환경에서 널리 사용되는 서버에서 제공 한 sendfile api를 사용해야합니다 . 몇 년 동안 나는 파일을 보호하기 위해이 서버의 sendfile api를 사용했습니다. 그런 다음 개발 및 생산 목적 모두에 적합한이 용도로 간단한 미들웨어 기반 장고 앱을 만들었습니다 . 여기 에서 소스 코드에 액세스 할 수 있습니다 .
업데이트 : 새 버전의 python공급자에서는 FileResponse가능한 경우 django 를 사용하고 lighthttp, caddy에서 hiawatha에 이르기까지 많은 서버 구현에 대한 지원을 추가합니다.
용법
pip install django-fileprovider
- 설정 에
fileprovider앱을 추가INSTALLED_APPS하고 - 추가
fileprovider.middleware.FileProviderMiddleware로MIDDLEWARE_CLASSES설정 - 설정 을 프로덕션으로
FILEPROVIDER_NAME설정nginx하거나apache프로덕션 환경으로 설정하십시오. 기본적으로python개발 목적입니다.
클래스 기반 또는 함수보기에서 응답 헤더 X-File값을 파일의 절대 경로로 설정 하십시오. 예를 들어
def hello(request):
// code to check or protect the file from unauthorized access
response = HttpResponse()
response['X-File'] = '/absolute/path/to/file'
return response
django-fileprovider 코드가 최소한의 수정 만 필요로하는 방식으로 실행됩니다.
Nginx 구성
직접 액세스로부터 파일을 보호하기 위해 구성을 다음과 같이 설정할 수 있습니다
location /files/ {
internal;
root /home/sideffect0/secret_files/;
}
여기서는 내부 nginxURL /files/에만 액세스 할 위치 URL을 설정합니다. 위의 구성을 사용하는 경우 X-File을 다음과 같이 설정할 수 있습니다.
response['X-File'] = '/files/filename.extension'
nginx 구성 으로이 작업을 수행하면 파일이 보호되고 django에서 파일을 제어 할 수 있습니다 views
Django는 다른 서버를 사용하여 정적 미디어를 제공하는 것이 좋습니다 (동일한 컴퓨터에서 실행되는 다른 서버는 괜찮습니다) . lighttp 같은 서버를 사용하는 것이 좋습니다 .
이것은 설정이 매우 간단합니다. 하나. 요청에 따라 'somefile.txt'가 생성되면 (콘텐츠가 동적 임) django가 제공하도록 할 수 있습니다.
def qrcodesave(request):
import urllib2;
url ="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=s&chld=H|0";
opener = urllib2.urlopen(url);
content_type = "application/octet-stream"
response = HttpResponse(opener.read(), content_type=content_type)
response["Content-Disposition"]= "attachment; filename=aktel.png"
return response
살펴볼 또 다른 프로젝트 : http://readthedocs.org/docs/django-private-files/en/latest/usage.html 어렴풋이 보이지만 아직 테스트하지는 않았습니다.
기본적으로 프로젝트는 mod_xsendfile 구성을 추상화하고 다음과 같은 작업을 수행 할 수 있습니다.
from django.db import models
from django.contrib.auth.models import User
from private_files import PrivateFileField
def is_owner(request, instance):
return (not request.user.is_anonymous()) and request.user.is_authenticated and
instance.owner.pk = request.user.pk
class FileSubmission(models.Model):
description = models.CharField("description", max_length = 200)
owner = models.ForeignKey(User)
uploaded_file = PrivateFileField("file", upload_to = 'uploads', condition = is_owner)
나는 xsendfile 모듈과 auth view 데코레이터 django-filelibrary를 사용하여 동일한 문제에 대해 한 번 이상 직면했습니다 . 자신의 솔루션에 대한 영감으로 자유롭게 사용하십시오.
https://github.com/danielsokolowski/django-filelibrary
https://github.com/johnsensible/django-sendfile을 사용하여 정적 HTML 폴더에 대한 보호 된 액세스 제공 : https://gist.github.com/iutinvg/9907731
나는 이것에 대한 프로젝트를했다. 내 github repo를 볼 수 있습니다.
https://github.com/nishant-boro/django-rest-framework-download-expert
이 모듈은 Apache 모듈 Xsendfile을 사용하여 django rest 프레임 워크에서 다운로드 할 파일을 제공하는 간단한 방법을 제공합니다. 또한 특정 그룹에 속한 사용자에게만 다운로드를 제공하는 추가 기능이 있습니다
참고 URL : https://stackoverflow.com/questions/1156246/having-django-serve-downloadable-files
'development' 카테고리의 다른 글
| 다른 선택적 매개 변수를 생략하면서 선택적 매개 변수를 전달하는 방법은 무엇입니까? (0) | 2020.04.16 |
|---|---|
| Windows 응용 프로그램 아이콘에는 어떤 아이콘 크기가 포함되어야합니까? (0) | 2020.04.16 |
| “* this에 대한 rvalue 참조”란 무엇입니까? (0) | 2020.04.16 |
| 약한 참조와 소유되지 않은 참조의 차이점은 무엇입니까? (0) | 2020.04.16 |
| 기존 Docker 컨테이너에 볼륨을 추가하려면 어떻게해야합니까? (0) | 2020.04.16 |