2016-09-28 95 views
0

我想讓Django只爲登錄用戶提供一些媒體文件(例如用戶上傳的文件)。由於我的網站流量很低,我想我會保持簡單,不要使用django-sendfile告訴Nginx何時提供文件。相反,我會讓Django/Gunicorn來完成這項工作。對我來說,這似乎簡單得多,對於低流量網站來說,這可能更安全。用django服務受保護的媒體文件

但是,組織文件存儲位置的最佳方式是什麼?媒體文件全部存儲在MEDIA_ROOT以下,該目錄由Nginx在製作中提供。如果我將文件上傳到MEDIA_ROOT/protected/,我必須告訴Nginx不要爲子目錄protected中的文件提供服務。

但這是一個好主意嗎?對我來說,允許Nginx首先訪問/media/然後保護子目錄/media/protected/似乎是一種冒險。最好不要使用MEDIA_ROOT的子目錄來存儲受保護的文件?

但是,如果我嘗試這樣快速和骯髒的在我的模型:

upload_to='../protected/documents/%Y/%m/' 

Django的抱怨:

SuspiciousFileOperation at /admin/core/document/add/ 
The joined path (/home/me/projects/project/protected/documents/2016/09/test.file) is located outside of the base path component (/home/me/projects/project/media) 

所以我的東西是不是很好的做法,「離開」 MEDIA_ROOT

存儲和提供受保護媒體文件的最佳解決方案是什麼?

我有這個在我的Django的設置:

回答

0

我現在用以下解決方案上來

MEDIA_ROOT = "/projects/project/media/" 
MEDIA_URL = "/media/ 

在我的模型做兩種:

document = models.FileField(upload_to="public/documents") 

document = models.FileField(upload_to="protected/documents") 

這樣,我現在在我的媒體文件目錄中有兩個子目錄'public'和'protected'。

Nginx或Djangos開發服務器只處理'public'子目錄中的文件。

對於Django的開發服務器:

if os.environ["ENVIRONMENT_TYPE"] == 'development': 
    urlpatterns += static(settings.MEDIA_URL + "public/", document_root=settings.MEDIA_ROOT + "public/") 

而對於Nginx的(用於生產):

location /media/public/ { 
    alias /projects/project/media/public/; 
} 

當我想爲一個受保護的文件,我執行以下操作:

在urls.py中:

url(r'^media/protected/documents/(?P<file>.*)$', core.views.serve_protected_document, name='serve_protected_document'), 

而且在views.py:

@login_required() 
def serve_protected_document(request, file): 
    document = get_object_or_404(ProtectedDocument, file="protected/documents/" + file) 

    # Split the elements of the path 
    path, file_name = os.path.split(file) 

    response = FileResponse(document.file,) 
    response["Content-Disposition"] = "attachment; filename=" + file_name 

    return response 

我將不勝感激任何意見!有更好的方法來實現這個嗎?

+0

我要尋找一個解決同樣的問題,但我沒有任何公共媒體,而且我不喜歡誤用Django來提供文件。但目前只有一句話。在使用文件響應之前不應該打開文件? https://docs.djangoproject.com/zh/1.10/ref/request-response/#fileresponse-objects – texnic

+0

@texnic檢查我的答案 –

0

你可以查看我的回答here。使用nginx服務器中的sendfile擴展,直接從視圖直接提供媒體文件(可能是大文件)效果不佳;下面添加nginx的配置首先

location /projects/project/media/{ 
    # this path is not public 
    internal; 
    # absolute path 
    alias /projects/project/media/; 
} 

更改視圖,

@login_required 
def serve_protected_document(request, file): 
    document = get_object_or_404(ProtectedDocument, file="protected/documents/" + file) 

    # Split the elements of the path 
    path, file_name = os.path.split(file) 

    response = HttpResponse() 
    response["Content-Disposition"] = "attachment; filename=" + file_name 
    # using http://github.com/instapk/django-fileprovider 
    response["X-File"] = document.name 
    return response