Имея Django служить загружаемые файлы
Я хочу, чтобы пользователи на сайте могли загружать файлы, пути которых скрыты, поэтому они не могут быть загружены напрямую.
например, я бы хотел, чтобы URL-адрес был примерно таким:"http://example.com/download/?f=somefile.txt
и на сервере я знаю, что все загружаемые файлы находятся в папке "/home/user/files/".
есть ли способ заставить Django обслуживать этот файл для загрузки, а не пытаться найти URL и просмотреть чтобы показать его?
14 ответов:
для "лучшего из обоих миров" вы можете объединить решение С. Лотта с модуль 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 набор вверх.
EDIT:
mimetype заменяется content_type для django 1.7
response = HttpResponse(content_type='application/force-download'
EDIT: Ибо
nginx
Регистрация этой, он используетX-Accel-Redirect
вместоapache
заголовок X-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 строк кода.
S. Lott имеет "хорошее" / простое решение, а elo80ka имеет "лучшее"/эффективное решение. Вот "лучшее" / среднее решение - нет установки сервера, но более эффективно для больших файлов, чем наивное исправление:
http://djangosnippets.org/snippets/365/
в принципе, Django по-прежнему обрабатывает обслуживание файла, но не загружает все это в память сразу. Это позволяет вашему серверу (медленно) обслуживать большой файл без увеличения объема памяти использование.
опять же, X-SendFile S. Lott по-прежнему лучше для больших файлов. Но если вы не можете или не хотите беспокоиться об этом, то это среднее решение обеспечит вам лучшую эффективность без хлопот.
очень просто но не эффективный или масштабируемый решение, вы можете просто использовать встроенный django
serve
вид. Это отлично подходит для быстрых прототипов или одноразовой работы, но, как уже упоминалось в этом вопросе, вы должны использовать что-то вроде apache или 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))
пробовал решение @Rocketmonkeys, но загруженные файлы хранились как *.Бин и даны случайные имена. Конечно, это не нормально. Добавление еще одной строки из @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 для ответов, получил идеальное решение, объединяющее все из них=)
выше было упомянуто, что метод mod_xsendfile не допускает символов, отличных от ASCII, в именах файлов.
по этой причине у меня есть патч, доступный для mod_xsendfile, который позволит отправлять любой файл, если имя закодировано url, и дополнительный заголовок:
X-SendFile-Encoding: url
отправлено также.
просто упомянуть FileResponse объект в Django 1.10
Edit: просто столкнулся с моим собственным ответом при поиске простого способа потоковой передачи файлов через Django, поэтому вот более полный пример (для будущего меня). Предполагается, что имя поля файла
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'), ...
попробуйте:https://pypi.python.org/pypi/django-sendfile/
"абстракция для разгрузки загрузки файлов на веб-сервер (например, Apache с mod_xsendfile) после того, как Django проверил разрешения и т. д."
вы должны использовать API sendfile, предоставленные популярными серверами, такими как
apache
илиnginx
в производстве. Много лет я использовал sendfile api этих серверов для защиты файлов. Затем создал простое приложение Django на основе промежуточного программного обеспечения для этой цели, подходящее как для разработки, так и для производства.Вы можете получить доступ к исходному коду здесь.
Обновление: в новой версииpython
провайдер использует djangoFileResponse
если доступно, а также добавляет поддержку для многих реализациях сервера от lighthttp, caddy to hiawathaиспользование
pip install django-fileprovider
- добавить
fileprovider
приложениеINSTALLED_APPS
параметры- добавить
fileprovider.middleware.FileProviderMiddleware
доMIDDLEWARE_CLASSES
настройки- set
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/; }
здесь
nginx
задает URL-адрес местоположения/files/
только доступ внутренний, если вы используете выше конфигурации вы можете установить X-файл как,response['X-File'] = '/files/filename.extension'
делая это с конфигурацией nginx, файл будет будьте защищены , а также вы можете управлять файлом из django
views
Django рекомендует использовать другой сервер для обслуживания статических носителей (другой сервер, работающий на той же машине, в порядке.) Они рекомендуют использовать такие серверы как lighttp.
Это очень просто настроить. Однако. если ' какой-то файл.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 decorators django-filelibrary. Не стесняйтесь использовать его в качестве вдохновения для собственного решения.
предоставление защищенного доступа к статической папке html с помощью https://github.com/johnsensible/django-sendfile: https://gist.github.com/iutinvg/9907731