Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django upload file into specific directory that depends on the POST URI

I'd like to store uploaded files into a specific directory that depends on the URI of the POST request. Perhaps, I'd also like to rename the file to something fixed (the name of the file input for example) so I have an easy way to grep the file system, etc. and also to avoid possible security problems.

What's the preferred way to do this in Django?

Edit: I should clarify that I'd be interested in possibly doing this as a file upload handler to avoid writing a large file twice to the file system.

Edit2: I suppose one can just 'mv' the tmp file to a new location. That's a cheap operation if on the same file system.

like image 445
kmt Avatar asked Feb 16 '10 23:02

kmt


2 Answers

Fixed olooney example. It is working now

@csrf_exempt
def upload_video_file(request):
    folder = 'tmp_dir2/' #request.path.replace("/", "_")
    uploaded_filename = request.FILES['file'].name
    BASE_PATH = '/home/'
    # create the folder if it doesn't exist.
    try:
        os.mkdir(os.path.join(BASE_PATH, folder))
    except:
        pass

    # save the uploaded file inside that folder.
    full_filename = os.path.join(BASE_PATH, folder, uploaded_filename)
    fout = open(full_filename, 'wb+')

    file_content = ContentFile( request.FILES['file'].read() )

    try:
        # Iterate through the chunks.
        for chunk in file_content.chunks():
            fout.write(chunk)
        fout.close()
        html = "<html><body>SAVED</body></html>"
        return HttpResponse(html)
    except:
        html = "<html><body>NOT SAVED</body></html>"
        return HttpResponse(html)
like image 196
user2455668 Avatar answered Oct 21 '22 09:10

user2455668


Django gives you total control over where (and if) you save files. See: http://docs.djangoproject.com/en/dev/topics/http/file-uploads/

The below example shows how to combine the URL and the name of the uploaded file and write the file out to disk:

def upload(request):
    folder = request.path.replace("/", "_")
    uploaded_filename = request.FILES['file'].name

    # create the folder if it doesn't exist.
    try:
        os.mkdir(os.path.join(BASE_PATH, folder))
    except:
        pass

    # save the uploaded file inside that folder.
    full_filename = os.path.join(BASE_PATH, folder, uploaded_filename)
    fout = open(full_filename, 'wb+')
    # Iterate through the chunks.
    for chunk in fout.chunks():
        fout.write(chunk)
    fout.close()

Edit: How to do this with a FileUploadHandler? It traced down through the code and it seems like you need to do four things to repurpose the TemporaryFileUploadHandler to save outside of FILE_UPLOAD_TEMP_DIR:

  1. extend TemporaryUploadedFile and override init() to pass through a different directory to NamedTemporaryFile. It can use the try mkdir except for pass I showed above.

  2. extend TemporaryFileUploadHandler and override new_file() to use the above class.

  3. also extend init() to accept the directory where you want the folder to go.

  4. Dynamically add the request handler, passing through a directory determined from the URL:

    request.upload_handlers = [ProgressBarUploadHandler(request.path.replace('/', '_')]

While non-trivial, it's still easier than writing a handler from scratch: In particular, you won't have to write a single line of error-prone buffered reading. Steps 3 and 4 are necessary because FileUploadHandlers are not passed request information by default, I believe, so you'll have to tell it separately if you want to use the URL somehow.

I can't really recommend writing a custom FileUploadHandler for this. It's really mixing layers of responsibility. Relative to the speed of uploading a file over the internet, doing a local file copy is insignificant. And if the file's small, Django will just keep it in memory without writing it out to a temp file. I have a bad feeling that you'll get all this working and find you can't even measure the performance difference.

like image 28
olooney Avatar answered Oct 21 '22 11:10

olooney