如何在 Django 实现文件上传

Posted on Wed, 25 Dec 2024 11:07:06 +0800 by LiangMingJian


概述

获取文件二进制数据 > 通过接口传递 > 写入服务器保存。

获取文件二进制数据

在 HTML 中使用 <input type="file">,能让用户选择一个或多个文件打开。

支持的参数:accept, capture, files, multiple

accept

accept 属性是一个字符串,它定义了文件 input 应该接受的文件类型。这个字符串是一个以逗号为分隔的唯一文件类型说明符列表。

<input type="file" id="docpicker" accept=".doc,.docx">

唯一文件类型说明符可使用如下格式:

  • 文件的扩展名:.jpg.pdf
  • MIME 类型字符串:audio/*video/*image/*

capture

capture 属性是一个字符串,当 input 打开的内容是图片或视频时,则它指定了使用哪个摄像头去捕获这些数据。

files

FileList 对象为每个已选择的文件。如果 multiple 属性没有指定,则这个列表只有一个成员。

可以通过const numFiles = files.length;来获取 FileList 列表的长度,可以像数组一样简单地访问文件列表来检索各个 File 对象。

for (let i = 0, numFiles = files.length; i < numFiles; i++) {
  const file = files[i];
  // ...
}

multiple

复数,是否允许选择多个。

通过接口传递数据

在获取 File 数据后,我们通过接口上传文件。

// 选择 input 的 files,由于不允许复数,因此可以直接取 FileList 的第一个数据
const selectedFile = document.getElementById('input-file').files[0];
// 构建 FormData 数据,将文件数据写入 FormData
var fileData = new FormData();
fileData.append('avatar', selectedFile);
// 通过接口传递
$.ajax({
    type: 'post',
    url: '/api/upload',
    cache: false,
    // 数据不需要编码,contentType 置假
    contentType: false,
    processData: false,
    // 传递 FormData 数据
    data: fileData,
    headers: { 'X-CSRFToken': csrftoken },
    success: function(res) {
        if(res.status == '10000'){
            console.log('success')
        }
    }
})

写入服务器保存

通过 FormData 传递的文件数据,在服务器中可以通过 request.FILES 获取,然后再根据属性获取到指定的 File 数据。

file_data = request.FILES
file = file_data.get('avatar')

编写函数,写入数据。

def handle_uploaded_file(file):
    ext = file.name.split('.')[-1]
    if ext in ['html', 'htm', 'js', 'css', 'php']:
        return 0
    file_name = '{}.{}'.format(uuid.uuid4().hex[:10], ext)
 
    # file path relative to 'media' folder
    absolute_file_path = os.path.join('main/media', file_name)
 
    directory = os.path.dirname(absolute_file_path)
    if not os.path.exists(directory):
        os.makedirs(directory)

    with open(absolute_file_path, 'wb+') as destination:
        for chunk in file.chunks():
            destination.write(chunk)

    return file_name

文件的读取

通过指定MEDIA_URL MEDIA_ROOT的值,用户可以在前端读取上传的数据。

# 在 setting.py 文件中写入如下配置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 在 url.py 中配置路由
re_path(r'media/(?P<path>.*)$',serve,{'document_root':settings.MEDIA_ROOT}),

按上配置后,用户可以通过 IP/media/文件名 来读取上传内容。