Django डाउनलोड करने योग्य फ़ाइलों की सेवा कर रहा है


245

मैं चाहता हूं कि साइट पर उपयोगकर्ता उन फ़ाइलों को डाउनलोड करने में सक्षम हों जिनके पथ अस्पष्ट हैं, इसलिए उन्हें सीधे डाउनलोड नहीं किया जा सकता है।

उदाहरण के लिए, मैं चाहूंगा कि URL कुछ इस तरह हो: http://example.com/download/?f=somefile.txt

और सर्वर पर, मुझे पता है कि सभी डाउनलोड करने योग्य फाइलें फ़ोल्डर में रहती हैं /home/user/files/

क्या Django को डाउनलोड करने के लिए उस फ़ाइल को डाउनलोड करने का एक तरीका है जो URL खोजने की कोशिश कर रहा है और इसे प्रदर्शित करने के लिए देखें?


2
ऐसा करने के लिए आप केवल अपाचे का उपयोग क्यों नहीं कर रहे हैं? अपाचे स्टैटिक कंटेंट को जिंजो की तुलना में अधिक तेजी से और आसानी से पेश करता है।
S.Lott

22
मैं अपाचे का उपयोग नहीं कर रहा हूं क्योंकि मैं नहीं चाहता कि फाइलें बिना अनुमति के सुलभ हों जो कि Django में आधारित हैं।
डेमन जू

3
यदि आप उपयोगकर्ता की अनुमतियों को ध्यान में रखना चाहते हैं, तो आपको Django के दृश्य के माध्यम से फ़ाइल
परोसनी होगी

127
वास्तव में, यही कारण है कि मैं यह सवाल पूछ रहा हूं।
डेमन जूल

जवाबों:


189

"दोनों दुनिया के सर्वश्रेष्ठ" के लिए आप एस.लॉट के समाधान को xsendfile मॉड्यूल के साथ जोड़ सकते हैं : django फ़ाइल (या फ़ाइल को स्वयं) के लिए पथ उत्पन्न करता है, लेकिन वास्तविक फ़ाइल सेवा Apache / Lighttdd द्वारा नियंत्रित की जाती है। एक बार जब आप 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 पहले से सेट हो।

संपादित करें:

mimetype को django 1.7 के लिए content_type द्वारा बदल दिया गया है

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

संपादित करें: के लिए nginxजाँच इस , यह का उपयोग करता है X-Accel-Redirectके बजाय apacheएक्स Sendfile हैडर।


6
यदि आपके फ़ाइल नाम, या path_to_file में "ä" या "ö" जैसे गैर-एससीआई अक्षर शामिल हैं, तो यह अपेक्षानुसार smart_strकाम नहीं करता है क्योंकि Apache मॉड्यूल X-Sendfile smart_str एन्कोडिंग स्ट्रिंग को डिकोड नहीं कर सकता है। इस प्रकार उदाहरण के लिए "ärinää.mp3" फ़ाइल परोसी नहीं जा सकती। और अगर कोई स्मार्ट_स्ट्रस्ट को छोड़ देता है, तो Django खुद ही एएससीआई एन्कोडिंग त्रुटि को फेंक देता है क्योंकि भेजने से पहले सभी हेडर को एएससीआई प्रारूप में एन्कोड किया जाता है। इस समस्या को दरकिनार करने का एकमात्र तरीका मुझे पता है कि एक्स-सेंडाइल फाइलनाम को कम करने के लिए केवल एससीआई शामिल हैं।
Ciantic

3
अधिक स्पष्ट होने के लिए: एस.लॉट का सरल उदाहरण है, बस सीधे django से फ़ाइलों की सेवा करना, किसी अन्य सेटअप की आवश्यकता नहीं है। elo80ka का अधिक कुशल उदाहरण है, जहां वेब-सर्वर स्थिर फ़ाइलों को संभालता है और django को नहीं करना पड़ता है। उत्तरार्द्ध में बेहतर प्रदर्शन है, लेकिन अधिक सेटअप की आवश्यकता हो सकती है। दोनों के अपने स्थान हैं।
राकेटमोनकीज

1
@Ciantic, एन्कोडिंग समस्या के समाधान की तरह दिखने के लिए btimby का जवाब देखें।
mlissner

क्या यह समाधान निम्नलिखित वेब सर्वर कॉन्फ़िगरेशन के साथ काम करता है? बैक-एंड: 2 या अधिक अपाचे + mod_wsgi व्यक्तिगत (VPS) सर्वर एक दूसरे को दोहराने के लिए स्थापित किए गए हैं। फ्रंट-एंड: 1 nginx प्रॉक्सी (VPS) सर्वर अपस्ट्रीम लोड बैलेंसिंग का उपयोग करते हुए, राउंड-रॉबिन करता है।
डेनियल

12

88

एक "डाउनलोड" बस एक HTTP हेडर परिवर्तन है।

Http://docs.djangoproject.com/en/dev/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment देखें कि कैसे डाउनलोड के साथ प्रतिक्रिया दें ।

इसके लिए आपको केवल एक URL परिभाषा चाहिए "/download"

अनुरोध GETया POSTशब्दकोश में "f=somefile.txt"जानकारी होगी ।

आपका व्यू फ़ंक्शन बस बेस पथ को " f" मान के साथ मर्ज करेगा , फ़ाइल खोलें, प्रतिक्रिया ऑब्जेक्ट बनाएँ और वापस करें। यह कोड की 12 लाइनों से कम होना चाहिए।


49
यह अनिवार्य रूप से सही (सरल) उत्तर है, लेकिन एक सावधानी - एक पैरामीटर के रूप में फ़ाइलनाम को पास करने का मतलब है कि उपयोगकर्ता संभावित रूप से किसी भी फ़ाइल को डाउनलोड कर सकता है (यानी क्या होगा यदि आप "f = / etc / passwd" पास करते हैं?) बहुत सारे हैं? उन चीजों की जो इसे रोकने में मदद करती हैं (उपयोगकर्ता की अनुमति, आदि), लेकिन बस इस स्पष्ट लेकिन सामान्य सुरक्षा जोखिम के बारे में पता होना चाहिए। यह मूल रूप से इनपुट को मान्य करने का एक सबसेट है: यदि आप किसी दृश्य में फ़ाइल नाम से गुजरते हैं, तो उस दृश्य में फ़ाइल नाम की जाँच करें!
रॉकेटमोंकी

9
इस सुरक्षा चिंता का एक बहुत ही सरल समाधान:filepath = filepath.replace('..', '').replace('/', '')
द्वंद्व_

7
यदि आप फ़ाइल जानकारी को संग्रहीत करने के लिए एक तालिका का उपयोग करते हैं, जिसमें उपयोगकर्ता इसे डाउनलोड करने में सक्षम होना चाहिए, तो आपको केवल भेजने की आवश्यकता है प्राथमिक कुंजी, फ़ाइल नाम नहीं है, और एप्लिकेशन यह तय करता है कि क्या करना है।
एडवर्ड नेवेल

30

एक बहुत ही सरल लेकिन कुशल या स्केलेबल समाधान के लिए, आप बस django serveदृश्य में निर्मित का उपयोग कर सकते हैं। यह त्वरित प्रोटोटाइप या वन-ऑफ़ काम के लिए उत्कृष्ट है, लेकिन जैसा कि इस पूरे प्रश्न में उल्लेख किया गया है, आपको उत्पादन में अपाचे या नग्नेक्स जैसी किसी चीज़ का उपयोग करना चाहिए।

from django.views.static import serve
filepath = '/some/path/to/local/file.txt'
return serve(request, os.path.basename(filepath), os.path.dirname(filepath))

विंडोज पर परीक्षण के लिए एक कमबैक प्रदान करने के लिए भी बहुत उपयोगी है।
अमीर अली अकबरी

मैं एक स्टैंडअलोन django प्रोजेक्ट कर रहा हूं, जिसका उद्देश्य एक डेस्कटॉप क्लाइंट की तरह काम करना है, और यह पूरी तरह से काम करता है। धन्यवाद!
डेगोरोकूब

1
यह कुशल क्यों नहीं है?
zinking

2
@zinking क्योंकि फाइलों को आम तौर पर django प्रक्रिया के माध्यम से अपाचे जैसी किसी चीज़ के माध्यम से परोसा जाना चाहिए
Cory

1
हम यहां किस तरह की प्रदर्शन कमियां बता रहे हैं? क्या फाइलें रैम में लोड हो जाती हैं या कुछ इस तरह की होती हैं अगर उन्हें django के माध्यम से परोसा जाए? Django nginx जैसी दक्षता के साथ सेवा करने में सक्षम क्यों नहीं है?
गेरशोम

27

S.Lott में "अच्छा" / सरल समाधान है, और elo80ka में "सर्वोत्तम" / कुशल समाधान है। यहाँ एक "बेहतर" / मध्य समाधान है - कोई सर्वर सेटअप नहीं, लेकिन बड़ी फ़ाइलों के लिए भोले निर्धारण की तुलना में अधिक कुशल:

http://djangosnippets.org/snippets/365/

असल में, Django अभी भी फ़ाइल की सेवा कर रहा है, लेकिन एक बार में पूरी चीज़ को मेमोरी में लोड नहीं करता है। यह आपके सर्वर को मेमोरी उपयोग को रैंप किए बिना (धीरे) एक बड़ी फ़ाइल की सेवा करने की अनुमति देता है।

फिर से, S.Lott की X-SendFile अभी भी बड़ी फ़ाइलों के लिए बेहतर है। लेकिन अगर आप इससे परेशान नहीं होना चाहते या नहीं कर सकते हैं, तो यह मध्य समाधान आपको परेशानी के बिना बेहतर दक्षता प्राप्त कराएगा।


4
वह स्निपेट अच्छा नहीं है। यह स्निप django.core.servers.httpbaseअनिर्धारित निजी मॉड्यूल पर निर्भर करता है , जिसमें कोड " DON'T USE FOR PRODUCTION USE !!! " के शीर्ष पर एक बड़ा चेतावनी चिन्ह है , जो पहली बार निर्मित होने के बाद से फाइल में है । किसी भी घटना में, FileWrapperइस स्निपेट पर निर्भरता की कार्यक्षमता django 1.9 में हटा दी गई है।
आंखों की रोशनी

16

@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

अब आप फ़ाइलों को एक निजी निर्देशिका में (मीडिया / न ही / public_html के अंदर) स्टोर कर सकते हैं और उन्हें कुछ उपयोगकर्ताओं या कुछ विशेष परिस्थितियों में django के माध्यम से उजागर कर सकते हैं।
आशा करता हूँ की ये काम करेगा।

उत्तर के लिए @ elo80ka, @ S.Lott और @Rocketmonkeys को धन्यवाद, उन सभी के संयोजन का सही समाधान मिला))


1
धन्यवाद, यह वही था जो मैं देख रहा था!
इटाकेचे

1
फ़ाइल नाम filename="%s"में रिक्त स्थान की समस्या से बचने के लिए, सामग्री-विवाद शीर्षक में फ़ाइल नाम के आसपास दोहरे उद्धरण जोड़ें । सन्दर्भ: रिक्त स्थान वाले फ़ाइलनामों को डाउनलोड पर छोटा कर दिया जाता है , HTTP में कंटेंट-डिस्पोजल हेडर के फ़ाइलनाम पैरामीटर को कैसे एनकोड करना है?
क्रिश्चियन लॉन्ग

1
आपके समाधान मेरे लिए काम करते हैं। लेकिन मेरी फ़ाइल के लिए "अमान्य प्रारंभ बाइट ..." त्रुटि थी। इसे हल कियाFileWrapper(open(path.abspath(file_name), 'rb'))
मार्क मिशिन

FileWrapperDjango 1.9 के बाद से हटा दिया गया है
freethebees

का उपयोग करना संभव हैfrom wsgiref.util import FileWrapper
Kriss

15

सिर्फ 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'),
...

1
आपका बहुत बहुत धन्यवाद! यह बाइनरी फ़ाइलों को डाउनलोड करने का सबसे सरल उपाय है और यह काम करता है।
जूलिया झाओ

13

ऊपर उल्लेख किया गया था कि mod_xsendfile विधि फ़ाइल नाम में गैर-ASCII वर्णों के लिए अनुमति नहीं देती है।

इस कारण से, मेरे पास mod_xsendfile के लिए एक पैच उपलब्ध है जो किसी भी फाइल को भेजने की अनुमति देगा, जब तक कि नाम url एन्कोडेड नहीं है, और अतिरिक्त हेडर:

X-SendFile-Encoding: url

के रूप में भी भेजा जाता है।

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


पैच को अब कोरर लाइब्रेरी में बदल दिया गया है।
mlissner

7

कोशिश करें: https://pypi.python.org/pypi/django-sendfile/

एक बार Django द्वारा अनुमतियों आदि की जाँच करने के बाद वेब-सर्वर पर उदासीन फ़ाइल अपलोड (जैसे कि mod_xsendfile के साथ अपाचे) में अमूर्तन


2
उस समय (1 वर्ष पहले) मेरे व्यक्तिगत कांटे में अपाचे फाइल थी जो कि मूल भंडार में से एक है।
रॉबर्टो रोसारियो

आपने लिंक क्यों हटाया?
कियोका ४६

@ kiok46 जीथब नीतियों के साथ संघर्ष। विहित पते की ओर इशारा किया।
रॉबर्टो रोजारियो

6

आपको लोकप्रिय सर्वर जैसे apacheया nginx उत्पादन में दिए गए सेंडफाइल एपिस का उपयोग करना चाहिए । कई वर्षों से मैं फ़ाइलों की सुरक्षा के लिए इन सर्वरों के सेंडल एप का उपयोग कर रहा था। फिर इस उद्देश्य के लिए एक साधारण मिडलवेयर आधारित django ऐप बनाया, जो विकास और उत्पादन दोनों उद्देश्य के लिए उपयुक्त है । आप यहाँ स्रोत कोड तक पहुँच सकते हैं
अद्यतन: यदि उपलब्ध हो तो नए संस्करण pythonप्रदाता में django का उपयोग किया जाता FileResponseहै और यह भी lIIIttp, 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/;
 }

यहाँ nginxएक स्थान सेट करता है url /files/केवल आंतरिक रूप से एक्सेस करता है, यदि आप उपरोक्त कॉन्फ़िगरेशन का उपयोग कर रहे हैं, तो आप X-File को सेट कर सकते हैं,

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

Nginx कॉन्फ़िगरेशन के साथ ऐसा करने से, फ़ाइल सुरक्षित हो जाएगी और साथ ही आप फ़ाइल को django से नियंत्रित कर सकते हैं views


2

Django अनुशंसा करता है कि आप स्थिर मीडिया की सेवा करने के लिए किसी अन्य सर्वर का उपयोग करें (उसी मशीन पर चलने वाला एक अन्य सर्वर ठीक है।) वे ऐसे सर्वरों का उपयोग लाइटटैप के रूप में करने की सलाह देते हैं ।

यह स्थापित करने के लिए बहुत सरल है। तथापि। यदि अनुरोध पर 'somefile.txt' उत्पन्न होता है (सामग्री गतिशील है) तो आप चाहते हैं कि django इसे सेवा दे सके।

Django डॉक्स - स्टेटिक फाइलें


2
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 

0

एक अन्य परियोजना पर एक नज़र है: http://readthedocs.org/docs/django-pStreet-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)

1
request.user.is_authenticated एक विधि है, विशेषता नहीं। (not request.user.is_anonymous ()) request.user.is_authenticated () के समान सटीक है क्योंकि is_authenticated is_anonymous का व्युत्क्रम है।
विस्फोट हुआ

@explodes सबसे खराब, यह कोड डॉक्स से सही है django-private-files...
आर्मंडो पेरेज़ मार्केज़

0

मुझे एक ही समस्या का सामना करना पड़ा है और फिर एक बार और इसलिए xsendfile मॉड्यूल और डीजेड व्यू डेकोरेटरों का उपयोग करके django-filelibrary का उपयोग किया गया है । इसे अपने स्वयं के समाधान के लिए प्रेरणा के रूप में उपयोग करने के लिए स्वतंत्र महसूस करें।

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



0

मैंने इस पर एक प्रोजेक्ट किया। आप मेरे गितुब रेपो को देख सकते हैं:

https://github.com/nishant-boro/django-rest-framework-download-expert

यह मॉड्यूल Apache मॉड्यूल Xsendfile का उपयोग करके django बाकी ढांचे में डाउनलोड के लिए फ़ाइलों की सेवा करने का एक सरल तरीका प्रदान करता है। इसमें केवल एक विशेष समूह से संबंधित उपयोगकर्ताओं को डाउनलोड करने की एक अतिरिक्त सुविधा है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.