views:

59

answers:

2

I have successfully uploaded an image using the following code:

views.py

from django.conf.urls.defaults import *
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from django import template
from django.template import RequestContext

from mysite.uploadr.forms import UploadFileForm

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            form.handle_uploaded_file(request.FILES['file'])
            return HttpResponse(template.Template('''
                        <html><head><title>Uploaded</title></head> <body>
                        <h1>Uploaded</h1>
                        </body></html>
                        '''
                        ).render( template.Context({}))
                    )
    else:  
        form = UploadFileForm()
    return render_to_response('upload.html', {'form': form}, context_instance=RequestContext(request))

forms.py

from django import forms
from settings import MEDIA_ROOT

class UploadFileForm(forms.Form):
    title = forms.CharField(max_length = 50)
    file = forms.FileField()

    def handle_uploaded_file(self,file):
        #print type(file), "file.name=",file.name
        #print dir(file)
        destination = open(MEDIA_ROOT + '/images/'+file.name, 'wb+')
        for chunk in file.chunks():
            destination.write(chunk)

I'd like to go one step further and associate an image with the user who is uploading. I've seen a few examples and have taken a liking to the technique in this post: http://stackoverflow.com/questions/3348013/django-image-file-uploads.

I noticed that their code uses save() and cleaned_data. Is it not necessary to iterate thru the chunks and write to the destination folder like the examples in the documentation? Do I have to use cleaned_data? Just trying to figure out the most efficient means of uploading files, I 've seen so many different ways of doing this. Your help you be greatly appreciated.

A: 

Chunking is needed when file is bigger than settings.FILE_UPLOAD_MAX_MEMORY_SIZE (default 2.5M in django 1.2)

Take a look at django.core.files.storage.FileSystemStorage class. It's save() method does the chunk-wise saving job for you and does the proper file locking.

storage = FileSystemStorage(
                    location = '/var/www/site/upfiles', 
                    base_url = '/upfiles'
                  )


content = request.FILES['the_file']
name = storage.save(None, content) #you can use some suggested name instead of
                                   #None. content.name will be used with None
url = storage.url(name)   #<-- get url for the saved file

In the older versions of django (e.g in 1.0) there was a defect in generation of file names. It kept adding _ to file names and the uploaded file name got longer and longer if you upload the same file repeatedly. This seems to be fixed in version 1.2.

Evgeny
A: 

By accessing request.FILES['file'] directly, you're bypassing any processing that your UploadFileForm is doing (you don't even need a form class to handle files like that). form.cleaned_data['file'] would access the processed (and cleaned, if you added a clean method) form data. You could also access the request.POST dictionary directly, instead of the form data. Unless you have a good reason to, it's better to use the cleaned form data.

In the example you gave, there was also a model being used (which is what the save() method was being called on), and it was the model's field that was handling the file access. If you want to save information about your uploaded files in a database, that's the way to go.

You can use the built-in file storage API for saving files: http://docs.djangoproject.com/en/dev/ref/files/storage/#ref-files-storage.

Also, it's not a good idea to simply call open(MEDIA_ROOT + '/images/'+file.name, 'wb+'), with the user-specified file name. That's just asking for directory traversal or other issues.

Bob