Upload file trong Django

Subscribe to my newsletter and never miss my upcoming articles

Khi Django xử lý tải lên tệp, dữ liệu tệp sẽ được đặt vào request.FILES. Bài viết này giải thích cách tệp được lưu trữ trên đĩa và trong bộ nhớ cũng như cách tùy chỉnh hành vi mặc định.

Cơ bản

Xét một form có chứa một trường FileField:

# forms.py

from django import forms

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

View xử lý form này sẽ nhận file tải lên từ request.FILES, là một từ điển với key là tên trường FileField (hoặc ImageField hoặc các lớp con của FileField khác) trong form. Cho nên file từ biểu mẫu trên được truy cập qua request.FILES['file'].

Chú ý rằng, request.FILES chỉ chứa dữ liệu nếu phương thức là POST, và có ít nhất một trường file được submit, đồng thời <form> phải có thuộc tính enctype"multipart/form-data". Nếu không request.FILES sẽ trống.

# views.py

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm

# Hàm xử lý file đã upload
from somewhere import handle_uploaded_file

def upload_file(request):
    if request.method == "POST":
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            return HttpResponseRedirect('/success/url/')
    else:
        form = UploadFileForm()
    return render(request, "upload.html", {"form": form})

Đây là cách phổ biến để xử lý file đã upload:

def handle_uploaded_file(f):
    with open('some/file/name.txt', 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

Xử lý file đã upload với một model

Nếu bạn lưu một file trong một Model với một trường FileField, sử dụng ModelForm giúp quá trình dễ dàng hơn. Đối tượng file sẽ được lưu vào thư mục cụ thể được đặt bởi đối số upload_to của FileField tương ứng khi gọi form.save():

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import ModelFormWithFileField

def upload_file(request):
    if request.method == "POST":
        form = ModelFormwithFileField(request.POST, request.FILES)
        if form.is_valid():
            # file sẽ được lưu
            form.save()
            return HttpReponseRedirect('/success/url/')
    else:
        form = ModelFormWithFileField()
    return render(request, "upload.html", {"form": form})

Nếu bạn xây dựng đối tượng của model bằng tay, bạn có thể gán đối tượng file từ request.FILES vào trường FileField trong model:

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from .models import ModelWithFileField

def upload_file(request):
    if request.method == "POST":
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            instance = ModelWithFileField(file_field=request.FILES['file'])
            instance.save()
            return HttpResponseRedirect('/success/url/')
    else:
        form = UploadFileForm()
    return render(request, "upload.html", {"form": form})

Upload nhiều file

Đầu tiên cần cài đặt thuộc tính multiple trong widget mặc định ClearableFileInput thông qua tùy chọn attrs:

# forms.py

from django import forms

class FileFieldForm(forms.Form):
    file_field = forms.FileField(widgets=forms.ClearableFileInput(attrs={'multiple': True})

Sau đó ghi đè phương thức post của class view FormView để xử lý các file đã upload:

# views.py

from django.views.generic.edit import FormView
from .forms import FileFieldForm

class FileFieldFormView(FormView):
    form_class = FileFieldForm
    template_name = 'upload.html'
    success_url = '...'

    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        files = request.FILES.getlist('file_field')
        if form.is_valid():
            for f in files:
                # Làm gì với mỗi file
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

No Comments Yet