
Django 要求包含文件上传的表单必须设置 enctype="multipart/form-data",否则 request.FILES 为空;但该属性不会影响 request.POST.get() 的正常使用——只要表单正确提交,两者可完全共存。
django 要求包含文件上传的表单必须设置 `enctype="multipart/form-data"`,否则 `request.files` 为空;但该属性不会影响 `request.post.get()` 的正常使用——只要表单正确提交,两者可完全共存。
在 Django 中,request.POST 和 request.FILES 是协同工作的两个独立数据容器:前者接收普通表单字段(如文本、下拉选项),后者专门接收上传的二进制文件。关键前提是:当表单中存在 <input type="file"> 时,HTML 表单标签 <form></form> 必须显式声明 enctype="multipart/form-data" —— 这是 HTTP 协议规范要求,而非 Django 的限制。
你当前的表单缺少该属性,导致浏览器以默认的 application/x-www-form-urlencoded 编码方式提交数据,此时文件内容根本不会被发送到服务端,request.FILES 自然为空,而 request.POST 仍能解析文本字段(因为其值被编码在请求体中),造成“文本可用、文件不可用”的错觉。
✅ 正确做法:仅需为表单添加 enctype 属性,其余逻辑无需改动:
<form action="{% url 'app' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<textarea name="testo" cols="30" rows="10"></textarea>
<label for="lang">Scegli lingua:</label>
<select name="lang">
<option value="it">Italiano</option>
<option value="en">Inglese</option>
<option value="es">Spagnolo</option>
</select>
<input type="file" name="audio">
<button type="submit">INVIA</button>
</form>对应视图中,你的原始 Python 代码完全有效:
from django.core.files.storage import FileSystemStorage
def your_view(request):
if request.method == 'POST':
testo = request.POST.get('testo') # ✅ 正常获取
lang = request.POST.get('lang') # ✅ 正常获取
audio = request.FILES.get('audio') # ✅ 推荐用 .get() 避免 KeyError
if audio: # 确保文件已上传
fs = FileSystemStorage()
filename = fs.save(audio.name, audio)
uploaded_file_url = fs.url(filename)
# 后续处理:保存模型、返回响应等
else:
# 处理无文件上传的情况
pass⚠️ 注意事项:
- 始终使用
request.FILES.get('field_name')替代request.FILES['field_name'],避免用户未选文件时触发MultiValueDictKeyError; -
enctype="multipart/form-data"不会影响 CSRF 保护、request.POST解析或任何其他 Django 表单机制; - 若使用 Django 表单类(
forms.Form或ModelForm),只需在实例化时传入request.POST和request.FILES即可自动分离处理; - 生产环境建议对上传文件做类型校验(如
audio.content_type.startswith('audio/'))、大小限制及安全重命名,避免直接使用audio.name。
总结:这不是 Django 的缺陷,而是 Web 标准的强制约定。添加 enctype 后,request.POST 和 request.FILES 将并行可靠工作——文本与文件,本就该一起上传。


















