Serve protected media files with django
I now came up with the following solution:
I have this in my Django settings:
MEDIA_ROOT = "/projects/project/media/"MEDIA_URL = "/media/
In my models I do either:
document = models.FileField(upload_to="public/documents")
or
document = models.FileField(upload_to="protected/documents")
This way, I now have the two subdirectories 'public' and 'protected' in my media files directory.
Nginx or Djangos development server only serves the files in the 'public' subdirectory.
For Djangos development server:
if os.environ["ENVIRONMENT_TYPE"] == 'development': urlpatterns += static(settings.MEDIA_URL + "public/", document_root=settings.MEDIA_ROOT + "public/")
And for Nginx (used in production):
location /media/public/ { alias /projects/project/media/public/;}
When I want to serve a protected document, I do the following:
In urls.py:
url(r'^media/protected/documents/(?P<file>.*)$', core.views.serve_protected_document, name='serve_protected_document'),
And in 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
I would appreciate any comments! Are there better ways to implement this?
Serving media files ( that may be large files) from view directly is not good. You can use sendfile
extension available in nginx server; a sample nginx configuration is like below.
location /projects/project/media/{ # this path is not public internal; # absolute path alias /projects/project/media/; }
change your view to
@login_requireddef 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 # nginx uses this path to serve the file response["X-Accel-Redirect"] = document.name # path to file return response
Link: More details on configuring sendfile extension on nginx is here