5

How can I allow users to upload files to their own, user designated folder, and only see files that they have uploaded? I am using django file-transfer. Currently it gives me a choice of what file to put the media in, but I can put it in any user's file and view every user's media. Here is my uploads/models.py:

from django.db import models
from django.contrib.auth.models import User, UserManager

def uploadmodel_file_upload_to(instance, filename):
    print 'instance.user.username = '+ str(instance.user.username)
    return 'uploads/%s/%s' % (instance.user.username, filename)

class UploadModel(models.Model):
    user = models.ForeignKey('auth.user')
    file = models.FileField(upload_to=uploadmodel_file_upload_to)
user784756
  • 2,363
  • 4
  • 28
  • 44
  • 1
    "Currently it gives me a choice"? "It"? What gives you a choice? – S.Lott Feb 26 '12 at 15:28
  • "It" being User. On the form it gives me a dropdown form with all of the users to choose from. – user784756 Feb 26 '12 at 15:40
  • "On the form it gives me a dropdown form "? Really? Does that mean you're using a default ModelForm for this Model? If so, please **update** the question to show this. And. What view function is being executing? Is this a default admin view? Or a view function you wrote? Please **update** the question to provide **all** the information. Please do not add comments. – S.Lott Feb 26 '12 at 16:11

1 Answers1

9

uploadmodel_file_upload_to returns a relative path. To build the full path, django prepends settings.MEDIA_ROOT. MEDIA_ROOT is supposed to be public readable.

So we want to save the file outside MEDIA_ROOT. Add something like this to settings.py:

import os.path
PROJECT_ROOT=os.path.abspath(os.path.dirname(__file__))
PROTECTED_MEDIA_ROOT=os.path.join(PROJECT_ROOT, 'protected_uploads')

Now you can update uploadmodel_file_upload_to to return an absolute path:

def uploadmodel_file_upload_to(instance, filename):
    return '%s/%s/%s' % (settings.PROTECTED_MEDIA_ROOT, instance.user.username,
        filename)

Now that the files are saved in /project/path/protected_uploads, we need to add a view to serve it, for example:

import os 
import mimetypes

from django import shortcuts
from django import http
from django.conf import settings
from django.views.static import was_modified_since
from django.utils.http import http_date

from .models import *

def serve_upload(request, upload_id):
    upload = shortcuts.get_object_or_404(UploadModel, pk=upload_id)
    fullpath = upload.file.path

    if request.user != upload.user:
        return http.HttpResponseForbidden()

    statobj = os.stat(fullpath)
    mimetype, encoding = mimetypes.guess_type(fullpath)
    mimetype = mimetype or 'application/octet-stream'
    if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
                              statobj.st_mtime, statobj.st_size):
        return http.HttpResponseNotModified(mimetype=mimetype)
    response = http.HttpResponse(open(fullpath, 'rb').read(), mimetype=mimetype)
    response["Last-Modified"] = http_date(statobj.st_mtime)
    response["Content-Length"] = statobj.st_size
    if encoding:
        response["Content-Encoding"] = encoding
    return response

And a URL:

url(r'serve_upload/(?P<upload_id>\d+)/$', 'serve_upload'),
jpic
  • 32,891
  • 5
  • 112
  • 113
  • If you are using caching, it might be useful not to cache the serve_upload calls if you don't want to get out of memory. from django.views.decorators.cache import never_cache @never_cache def serve_upload... – sogeking May 04 '15 at 09:14
  • Thanks @jpic , all of the above snippets are working good, one edit it needed i.e in line `response = http.HttpResponse(open(fullpath, 'rb').read(), content_type=mimetype)` Reference [link](https://stackoverflow.com/a/28758862/4402095) – Vikash Singh Jan 26 '22 at 13:23