Django serwuje pliki do pobrania

Chcę, aby użytkownicy serwisu mogli pobierać pliki, których ścieżki są zasłonięte, więc nie można ich bezpośrednio pobrać.

Na przykład, chciałbym, aby adres URL był czymś takim, " http://example.com/download/?f=somefile.txt

A na serwerze wiem, że wszystkie pliki do pobrania znajdują się w folderze "/home/user/files/".

Czy istnieje sposób, aby Django podawało ten plik do pobrania, zamiast próbować znaleźć adres URL i wyświetlić go?

Author: damon, 2009-07-21

14 answers

Dla" najlepszego z obu światów " możesz połączyć rozwiązanie S. Lotta z modułem xsendfile : django generuje ścieżkę do pliku (lub samego pliku), ale rzeczywiste serwowanie plików jest obsługiwane przez Apache/Lighttpd. Po skonfigurowaniu pliku mod_xsendfile, integracja z widokiem zajmuje kilka linijek kodu:

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

Oczywiście będzie to działać tylko wtedy, gdy masz kontrolę nad serwerem lub Twoja firma hostingowa ma ustawiony plik mod_xsendfile w górę.

EDIT:

Typ MIME jest zastąpiony przez content_type dla django 1.7

response = HttpResponse(content_type='application/force-download'  

EDIT: Dla nginx Sprawdź Ten, używa X-Accel-Redirect zamiast apache nagłówka X-Sendfile.

 170
Author: elo80ka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-15 12:19:55

"download" to po prostu zmiana nagłówka HTTP.

Zobacz http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment{[9]jak odpowiedzieć za pobraniem.

Potrzebujesz tylko jednej definicji URL dla "/download".

Słownik żądania GET lub POST będzie zawierał informacje "f=somefile.txt".

Funkcja widoku po prostu połączy ścieżkę bazową z wartością " f", otworzy plik, utworzy i zwróci obiekt odpowiedzi. Powinno być mniej niż 12 linijek kodu.

 79
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-20 23:20:15

S. Lott ma "dobre" / proste rozwiązanie, a elo80ka ma "najlepsze" / skuteczne rozwiązanie. Oto "lepsze" / środkowe rozwiązanie - brak konfiguracji serwera, ale bardziej wydajne dla dużych plików niż naiwna poprawka:

Http://djangosnippets.org/snippets/365/

Zasadniczo, Django nadal obsługuje serwowanie pliku, ale nie ładuje całości do pamięci na raz. Pozwala to serwerowi (powoli)obsługiwać duży plik bez zwiększania zużycia pamięci.

Znowu S. Lott ' s X-SendFile jest jeszcze lepszy dla większych plików. Ale jeśli nie możesz lub nie chcesz się tym przejmować, to środkowe rozwiązanie zapewni Ci lepszą wydajność bez kłopotów.

 26
Author: rocketmonkeys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-21 22:31:20

Dla bardzo prostego , ale nie wydajnego lub skalowalnego rozwiązania, możesz po prostu użyć wbudowanego widoku django serve. Jest to doskonałe rozwiązanie do szybkich prototypów lub jednorazowej pracy, ale jak już wspomniano w tym pytaniu, powinieneś użyć czegoś takiego jak apache lub nginx w produkcji.

from django.views.static import serve
filepath = '/some/path/to/local/file.txt'
return serve(request, os.path.basename(filepath), os.path.dirname(filepath))
 25
Author: Cory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-18 22:54:28

Próbowałem rozwiązania @ Rocketmonkeys, ale pobrane pliki były przechowywane jako *.bin i podane losowe nazwy. To oczywiście nie w porządku. Dodanie kolejnej linijki z @elo80ka rozwiązało problem.
Oto kod, którego teraz używam:

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

Możesz teraz przechowywać pliki w prywatnym katalogu (Nie wewnątrz /media ani /public_html) i udostępniać je przez django określonym użytkownikom lub w pewnych okolicznościach.
Mam nadzieję, że to pomoże.

podziękowania dla @elo80ka, @S. Lott i @Rocketmonkeys za odpowiedzi, mamy idealne rozwiązanie łączące je wszystkie =)

 13
Author: Salvatorelab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-13 23:41:14

Wspomniano powyżej, że metoda mod_xsendfile nie pozwala na użycie znaków innych niż ASCII w nazwach plików.

Z tego powodu mam dostępną łatkę dla mod_xsendfile, która pozwoli na wysłanie dowolnego pliku, o ile nazwa jest zakodowana url i dodatkowy nagłówek:

X-SendFile-Encoding: url

Jest również wysyłany.

Http://ben.timby.com/?p=149

 12
Author: btimby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-14 17:10:18

Wystarczy wspomnieć o obiekcie FileResponse dostępnym w Django 1.10

Edit: właśnie natknąłem się na moją własną odpowiedź podczas poszukiwania łatwego sposobu przesyłania strumieniowego plików przez Django, więc oto pełniejszy przykład(dla przyszłych mnie). Zakłada, że nazwa FileField to 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'),
...
 10
Author: shadi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-15 15:18:53

Try: https://pypi.python.org/pypi/django-sendfile/

" abstrakcja do odciążania przesyłanych plików na serwer WWW (np. Apache z mod_xsendfile) po sprawdzeniu uprawnień przez Django itp."

 6
Author: Roberto Rosario,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-22 08:47:36

Powinieneś używać sendfile API podanych przez popularne serwery, takie jak apache lub nginx w produkcji. Wiele lat używałem sendfile api tych serwerów do ochrony plików. Następnie stworzyłem do tego celu prostą aplikację django opartą na oprogramowaniu middleware, odpowiednią zarówno do celów programistycznych, jak i produkcyjnych.Możesz uzyskać dostęp do kodu źródłowego tutaj .
UPDATE: w nowej wersji python provider używa django FileResponse jeśli jest dostępny, a także dodaje wsparcie dla wielu implementacji Serwerów od lighttp, caddy do hiawatha

Użycie

pip install django-fileprovider
  • dodaj fileprovider aplikację do INSTALLED_APPS ustawienia,
  • dodaj fileprovider.middleware.FileProviderMiddleware do MIDDLEWARE_CLASSES ustawienia
  • Ustaw FILEPROVIDER_NAME na nginx lub apache w produkcji, domyślnie jest to python w celu rozwoju.

W widokach classbased lub function Ustaw nagłówek odpowiedzi X-File na bezwzględną ścieżkę do pliku. Na przykład,

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 w taki sposób, że Twój kod będzie potrzebował tylko minimum modyfikacja.

Konfiguracja Nginx

Aby chronić plik przed bezpośrednim dostępem, możesz ustawić konfigurację jako

 location /files/ {
  internal;
  root   /home/sideffect0/secret_files/;
 }

Tutaj nginx ustawia adres URL lokalizacji /files/ tylko dostęp wewnętrzny, jeśli używasz powyższej konfiguracji, możesz ustawić Plik X jako,

response['X-File'] = '/files/filename.extension' 

Robiąc to z konfiguracją nginx, plik będzie chroniony i możesz kontrolować Plik z django views

 5
Author: I Am Batman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-13 16:08:29

Django zaleca używanie innego serwera do serwowania statycznych multimediów (inny serwer działający na tej samej maszynie jest w porządku.) Zalecają korzystanie z takich serwerów jak lighttp.

Jest to bardzo proste w konfiguracji. Jednak. if ' somefile.txt ' jest generowany na żądanie (treść jest dynamiczna) wtedy możesz chcieć, aby django ją obsłużyło.

Django Docs-Static Files

 1
Author: kjfletch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-21 09:49:56
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 
 1
Author: Saurabh Chandra Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-21 10:12:41

Kolejny projekt do obejrzenia: http://readthedocs.org/docs/django-private-files/en/latest/usage.html Wygląda obiecująco, Sam jeszcze tego nie testowałem.

Zasadniczo projekt streszcza konfigurację pliku mod_xsendfile i pozwala na wykonanie takich rzeczy jak:

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)
 0
Author: thyagx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-13 06:18:31

Miałem do czynienia z tym samym problemem więcej niż raz i tak zaimplementowany przy użyciu modułu xsendfile i dekoratorów widoku auth django-filelibrary. Zachęcamy do wykorzystania go jako inspiracji dla własnego rozwiązania.

Https://github.com/danielsokolowski/django-filelibrary

 0
Author: Daniel Sokolowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-01 22:07:51

Zapewnienie bezpiecznego dostępu do statycznego folderu html za pomocą https://github.com/johnsensible/django-sendfile: https://gist.github.com/iutinvg/9907731

 0
Author: iutinvg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-01 04:35:39