Chcę, aby użytkownicy w witrynie mogli pobierać pliki, których ścieżki są zasłonięte, więc nie można ich pobrać bezpośrednio.
Na przykład chciałbym, aby adres URL był mniej więcej taki: 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 wyświetlał ten plik do pobrania, zamiast próbować znaleźć adres URL i wyświetlić, aby go wyświetlić?
Odpowiedzi:
Dla „najlepszego z obu światów” można połączyć rozwiązanie S.Lott z modułem xsendfile : django generuje ścieżkę do pliku (lub samego pliku), ale faktyczną obsługą plików zajmuje się Apache / Lighttpd. Po skonfigurowaniu pliku mod_xsendfile integracja z twoim widokiem zajmuje kilka linii kodu:
Oczywiście będzie to działać tylko wtedy, gdy masz kontrolę nad serwerem lub jeśli Twoja firma hostingowa ma skonfigurowany plik mod_xsendfile.
EDYTOWAĆ:
EDYCJA: Aby to
nginx
sprawdzić , używa zamiast nagłówka X-Sendfile.X-Accel-Redirect
apache
źródło
smart_str
to nie działa zgodnie z przeznaczeniem, ponieważ moduł X-Sendfile apache nie może dekodować ciągu zakodowanego w smart_str. Dlatego na przykład nie można podać pliku „Örinää.mp3”. A jeśli pominąć smart_str, sam Django generuje błąd kodowania ascii, ponieważ wszystkie nagłówki są kodowane do formatu ascii przed wysłaniem. Jedynym sposobem na obejście tego problemu jest zmniejszenie nazw plików X-sendfile do tych, które składają się tylko z ascii.„Pobieranie” 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, aby dowiedzieć się, jak odpowiedzieć przy pobieraniu .
Potrzebujesz tylko jednej definicji adresu URL dla
"/download"
.Żądanie
GET
lubPOST
słownik będzie zawierał"f=somefile.txt"
informacje.Twoja funkcja widoku po prostu połączy ścieżkę podstawową z wartością „
f
”, otworzy plik, utworzy i zwróci obiekt odpowiedzi. Powinien mieć mniej niż 12 linii kodu.źródło
filepath = filepath.replace('..', '').replace('/', '')
Aby uzyskać bardzo proste, ale nieefektywne lub skalowalne rozwiązanie, możesz po prostu użyć wbudowanego
serve
widoku django . Jest to doskonałe do szybkich prototypów lub jednorazowej pracy, ale jak wspomniano w tym pytaniu, powinieneś używać czegoś takiego jak apache lub nginx w produkcji.źródło
S.Lott ma „dobre” / proste rozwiązanie, a elo80ka ma „najlepsze” / wydajne rozwiązanie. Oto „lepsze” / środkowe rozwiązanie - bez konfiguracji serwera, ale bardziej wydajne dla dużych plików niż naiwna poprawka:
http://djangosnippets.org/snippets/365/
Zasadniczo Django nadal obsługuje udostępnianie pliku, ale nie ładuje całej pamięci naraz. Pozwala to serwerowi (powoli) podawać duży plik bez zwiększania zużycia pamięci.
Ponownie, X-SendFile S.Lott jest nadal lepszy dla większych plików. Ale jeśli nie możesz lub nie chcesz się tym przejmować, to to środkowe rozwiązanie zapewni Ci lepszą wydajność bez kłopotów.
źródło
django.core.servers.httpbase
nieudokumentowanym module prywatnym, który ma duży znak ostrzegawczy w górnej części kodu „ NIE UŻYWAJ DO UŻYTKU PRODUKCYJNEGO !!! ”, który znajduje się w pliku od momentu jego pierwszego utworzenia . W każdym razieFileWrapper
funkcjonalność, na której opiera się ten fragment kodu, została usunięta w wersji django 1.9.Próbowałem rozwiązania @Rocketmonkeys, ale pobrane pliki były przechowywane jako * .bin i otrzymywały losowe nazwy. Oczywiście to nie w porządku. Dodanie kolejnej linii z @ elo80ka rozwiązało problem.
Oto kod, którego teraz używam:
Możesz teraz przechowywać pliki w prywatnym katalogu (nie wewnątrz / media ani / public_html) i udostępniać je za pośrednictwem django pewnym użytkownikom lub w określonych okolicznościach.
Mam nadzieję, że to pomoże.
Dzięki @ elo80ka, @ S.Lott i @Rocketmonkeys za odpowiedzi, otrzymaliśmy idealne rozwiązanie łączące je wszystkie =)
źródło
filename="%s"
w nagłówku Content-Disposition, aby uniknąć problemów ze spacjami w nazwach plików. Odniesienia: Nazwy plików ze spacjami są obcinane podczas pobierania , Jak zakodować parametr nazwy nagłówka Content-Disposition w HTTP?FileWrapper(open(path.abspath(file_name), 'rb'))
FileWrapper
został usunięty od Django 1.9from wsgiref.util import FileWrapper
Wystarczy wspomnieć o obiekcie FileResponse dostępnym w Django 1.10
Edycja: Właśnie natrafiłem na własną odpowiedź, szukając łatwego sposobu przesyłania strumieniowego plików przez Django, więc oto bardziej kompletny przykład (dla mnie przyszłości). Zakłada się, że nazwa FileField to
imported_file
views.py
urls.py
źródło
Wspomniano powyżej, że metoda mod_xsendfile nie dopuszcza znaków innych niż ASCII w nazwach plików.
Z tego powodu mam łatkę do pliku mod_xsendfile, która pozwoli na wysłanie dowolnego pliku, o ile nazwa jest zakodowana w url, oraz dodatkowy nagłówek:
Jest również wysyłany.
http://ben.timby.com/?p=149
źródło
Spróbuj: https://pypi.python.org/pypi/django-sendfile/
„Abstrakcja w celu odciążenia przesyłania plików na serwer WWW (np. Apache z mod_xsendfile) po sprawdzeniu uprawnień przez Django itp.”
źródło
Powinieneś używać apli sendfile podanych przez popularne serwery, takie jak
apache
lubnginx
produkcyjne. Przez wiele lat korzystałem z interfejsu API sendfile tych serwerów do ochrony plików. Następnie stworzył prostą middleware w oparciu Django aplikacji do tego celu nadaje się zarówno do rozwoju i produkcji purpose.You może uzyskać dostęp do kodu źródłowego tutaj .AKTUALIZACJA: w nowej wersji
python
dostawca używa django,FileResponse
jeśli jest dostępny, a także dodaje obsługę wielu implementacji serwera, od lighthttp, caddy po hiawathaStosowanie
fileprovider
aplikację doINSTALLED_APPS
ustawień,fileprovider.middleware.FileProviderMiddleware
doMIDDLEWARE_CLASSES
ustawieńFILEPROVIDER_NAME
ustawienia nanginx
lubapache
w produkcji, domyślnie jest topython
do celów programistycznych.w widokach opartych na klasach lub funkcjach ustaw
X-File
wartość nagłówka odpowiedzi na bezwzględną ścieżkę do pliku. Na przykład,django-fileprovider
usprawnione w taki sposób, że Twój kod będzie wymagał jedynie minimalnej modyfikacji.Konfiguracja Nginx
Aby chronić plik przed bezpośrednim dostępem, możesz ustawić konfigurację jako
Tutaj
nginx
ustawia adres URL/files/
dostępu tylko wewnętrznie, jeśli używasz powyższej konfiguracji, możesz ustawić plik X jako,Robiąc to z konfiguracją nginx, plik będzie chroniony, a także możesz kontrolować plik z django
views
źródło
Django zaleca użycie innego serwera do obsługi nośników statycznych (inny serwer działający na tym samym komputerze jest w porządku) . Zalecają użycie takich serwerów jak lighttp .
Jest to bardzo proste w konfiguracji. Jednak. jeśli plik „somefile.txt” jest generowany na żądanie (treść jest dynamiczna), możesz chcieć, aby django go obsługiwał.
Dokumenty Django - pliki statyczne
źródło
źródło
Kolejny projekt do obejrzenia: http://readthedocs.org/docs/django-private-files/en/latest/usage.html Wygląda obiecująco, sam jeszcze go nie testowałem.
Zasadniczo projekt wyodrębnia konfigurację pliku mod_xsendfile i umożliwia wykonywanie następujących czynności:
źródło
django-private-files
...Napotkałem ten sam problem więcej niż raz i dlatego zaimplementowałem go za pomocą modułu xsendfile i dekoratorów widoku uwierzytelniania django-filelibrary . Możesz użyć go jako inspiracji do własnego rozwiązania.
https://github.com/danielsokolowski/django-filelibrary
źródło
Zapewnianie chronionego dostępu do statycznego folderu HTML za pomocą https://github.com/johnsensible/django-sendfile : https://gist.github.com/iutinvg/9907731
źródło
Zrobiłem projekt na ten temat. Możesz spojrzeć na moje repozytorium github:
https://github.com/nishant-boro/django-rest-framework-download-expert
Ten moduł zapewnia prosty sposób udostępniania plików do pobrania w środowisku odpoczynku django za pomocą modułu Apache Xsendfile. Ma także dodatkową funkcję udostępniania pobrań tylko użytkownikom należącym do określonej grupy
źródło