Tuesday, June 12, 2012

Django -- upload file

上傳資料,參考
http://oranlooney.com/django-file-uploads/
http://www.nitinh.com/2009/02/django-example-filefield-and-imagefield/
http://gibuloto.com/blog/models-dot-imagefield/ 

(1)設定上傳用的資料夾
Django 1.4 裡面有提供 MEDIA_URL 和 MEDIA_ROOT
這兩個部份的設定主要是讓使用者上傳資料和顯示

這邊就不從開新的app開始說,直接從settings.py和models.py設定開始

首先是settings.py的設定
cd //var/www/mutarock/mutarock
vim settings.py
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), '..', 'multimedia').replace('\\','/')
MEDIA_URL = '/multimedia/'
設定完之後移到上一層去
cd ..
mkdir multimedia
接下來是apps裡面models.py的設定
class Picture(models.Model):
    image = models.ImageField(upload_to='pic')

上面的models開了一個欄位,讓使用者上傳圖片,在django裡面,系統不會真的把東西儲存在資料庫裡面
而是儲存資料在系統裡面的位置

MEDIA_ROOT 和 upload_to 的設定,有以下的關係

MEDIA_ROOT = ‘/home/myname/files/
upload_to=’videos’
file: abc.flv
results in: /home/myname/files/videos/abc.flv

MEDIA_ROOT = '/home/myname/files/'
upload_to='/videos'
and file : abc.flv
result will be saved in : '/videos/abc.flv' (i.e., root directory of filesystem)

upload_to也可以加進去上傳的日期和時間
upload_to='videos/%Y/%m/%d'
如果上傳時間是2012 Jun 12
檔案就會儲存到 /home/myname/files/videos/2012/06/12

(2)設定form.py
form的部分可以直接建立在html裡面,網路上的參考文章則是順便教了如何用django實做form
連到自己的apps裡面新增一個form.py
vim form.py
輸入下面的code
from django import forms
from PIL import Image
class PictureUploadForm(forms.Form):
    image = forms.ImageField()
    

    def clean_image(self):
        ' reject large images.'
        max_size = 10**7
        if len(self.cleaned_data['image'].read()) > max_size:
            raise forms.ValidationError('Image must be less then %d bytes.' % max_size)
        else:
            return self.cleaned_data['image']

上面的code會有一個可以欄位,讓使用者決定要上傳什麼圖檔
其中也自訂一個function,檢查上傳的檔案是否超過我們自定的大小

(3)設定views.py
import uuid #use for data name
from apps.picture.form import PictureUploadForm  #import your form

def picture_upload(request):

    picture = Picture()
    if request.method != 'POST':
        form = PictureUploadForm()
    else:
        form = PictureUploadForm(request.POST, request.FILES)
        if form.is_valid():

            # an UploadedFile object
            uploadedImage = form.cleaned_data['image']
            file_name = uuid.uuid4().hex
            file_extension = os.path.splitext(uploadedImage.name)[-1]
            full_file_name = file_name + file_extension

            # save picture object
            picture.image.save(
                full_file_name, 
                request.FILES['image'], 
                save = False
            )
            picture.save()
            return render_to_response(
                'example/result.html'
                {'result': "Upload success",},
                context_instance = RequestContext(request))


    return render_to_response(
        'example/picture_upload.html',
        {'form':form},
        context_instance = RequestContext(request))

簡單說明上面的code
如果request不是POST,就只回傳form
如果是POST,則把使用者選擇的圖片上傳到系統裡面
檔名的部分我是用uuid,這樣幾乎可以確保檔案名稱不會重複
file_extension是檔案的格式,例如 jpg 或是 png
最後就印出"Upload success"給使用者


picture_upload.html
<form enctype="multipart/form-data" method="post" action="example/picture_upload">
    {% csrf_token %}   
    <table>
        {{form.as_p}}
    </table>
    <input type="submit" value="Submit" id="Save"/>
</form>

result.html
<p> {{ result }} </p>


上傳檔案大概就是這樣,主要就是設定好
MEDIA_ROOT
upload_to
大概就沒問題了


MEDIA_URL的部分是要讓使用者可以讀取或是顯示出上傳的東西
我是設定成
MEDIA_URL = '/multimedia/'
然後再主要的urls.py加上
urlpatterns += patterns('',
    url(r'^multimedia/(?P.*)$', 'django.views.static.serve',
                 {'document_root': settings.MEDIA_ROOT}),
所以我輸入
http://localhost:8000/multimedia/pic/FileName
就可以顯示出我上傳的圖片了


No comments: