在Django中,通常文件上传是通过表单的<input type="file">
元素实现的,但有时我们需要在不使用传统表单的情况下通过Ajax上传文件。这种技术在现代Web应用中非常常见,特别是在需要实现拖放上传或更灵活的文件选择界面时。
<!-- HTML部分 -->
<input type="file" id="file-input">
<button id="upload-btn">上传</button>
<div id="progress"></div>
<div id="result"></div>
<!-- JavaScript部分 -->
<script>
document.getElementById('upload-btn').addEventListener('click', function() {
const fileInput = document.getElementById('file-input');
const file = fileInput.files[0];
if (!file) {
alert('请先选择文件');
return;
}
const formData = new FormData();
formData.append('file', file);
formData.append('csrfmiddlewaretoken', '{{ csrf_token }}');
const xhr = new XMLHttpRequest();
// 上传进度监听
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
document.getElementById('progress').innerHTML = `上传进度: ${percent}%`;
}
});
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
document.getElementById('result').innerHTML = '上传成功: ' + xhr.responseText;
} else {
document.getElementById('result').innerHTML = '上传失败: ' + xhr.statusText;
}
}
};
xhr.open('POST', '/upload/', true);
xhr.send(formData);
});
</script>
# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import os
from django.conf import settings
@csrf_exempt # 仅用于示例,生产环境应使用其他CSRF保护方式
def upload_file(request):
if request.method == 'POST' and request.FILES.get('file'):
uploaded_file = request.FILES['file']
# 确保上传目录存在
upload_dir = os.path.join(settings.MEDIA_ROOT, 'uploads')
os.makedirs(upload_dir, exist_ok=True)
# 保存文件
file_path = os.path.join(upload_dir, uploaded_file.name)
with open(file_path, 'wb+') as destination:
for chunk in uploaded_file.chunks():
destination.write(chunk)
return JsonResponse({
'status': 'success',
'message': '文件上传成功',
'file_name': uploaded_file.name,
'file_size': uploaded_file.size
})
return JsonResponse({
'status': 'error',
'message': '无效的请求或未选择文件'
}, status=400)
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('upload/', views.upload_file, name='upload_file'),
]
原因:Django默认要求所有POST请求包含CSRF令牌
解决方案:
@csrf_exempt
装饰器(仅用于测试)原因:服务器或客户端有大小限制
解决方案:
DATA_UPLOAD_MAX_MEMORY_SIZE
设置解决方案:
// 前端验证
const allowedTypes = ['image/jpeg', 'image/png'];
if (!allowedTypes.includes(file.type)) {
alert('只允许上传JPEG或PNG图片');
return;
}
# 后端验证
allowed_types = ['image/jpeg', 'image/png']
if uploaded_file.content_type not in allowed_types:
return JsonResponse({'error': '文件类型不允许'}, status=400)
通过这种方式,你可以实现灵活、高效的文件上传功能,而不受传统表单的限制。