You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中如何从文件输入元素提取文件名?

问题描述

我想在Django中实现一个表单,其中一个输入项是文件名列表。不需要访问或上传文件本身,只需要便捷获取文件名列表,再和其他表单数据一起提交。

我尝试用模板里的多文件输入元素,通过htmx提取文件名,但不管怎么操作,都只能得到字符串%5Bobject%20File%5D(解码后是[object File]),拿不到实际文件名。

以下是简化后的代码:

urls.py

from django.urls import path
from .views import *

urlpatterns = [
    path("home_1b/", home_1b, name="home_1b"),
    path("", home, name="home"),
]

views.py

from django.shortcuts import render

def home(request):
    return render(request,'home.html')

def home_1b(request):
    print('*********************')
    print(request)
    print(request.GET)
    print(request.GET['fi_file_names'])
    print(request.FILES)
    print('*********************')
    return render(request,'home_1b.html')

home.html

<!-- templates/home.html -->
{% extends "base.html" %}
{% block head %}
{% load static %}
<script src="{% static '/htmx/htmx.min.js' %}"></script>
<style>
    .column {float:left; width:50%;}
    .row:after{content:""; display:table; clear:both;}
    label {font-family:Verdana; font-size:small;}
    input[type="file"] {width:350px; padding:1px 3px 1px 3px; font-family:Verdana; font-size:small;  border-style:solid; border-width:1px; background-color:lightgray;}
    input[type="file"]::file-selector-button {display:none;}
</style>
{% endblock head %}
{% block content %}
<h2>File name entry</h2>
<div id="home_r1c1" class="row">
    <h3>Enter the file name(s) to be cited in the report</h3>
    <div id="home_1a_slot" 
    hx-get="{% url 'home_1b' %}"
    hx-trigger="change"
    hx-encoding="multipart/form-data"
    hx-target="#home_1b_slot"
    hx-include="#fi_file_names">
        <label for="fi_file_names" style="border:1px solid; border-radius:3px; padding:1px 5px 1px 5px; background-color:lightgray;">...</label>
        <input type='file' multiple id="fi_file_names" name="fi_file_names"></input>
    </div>
    <h3>Review the files specified</h3>
    <div id="home_1b_slot">
    </div>
</div>
{% endblock content %}

运行输出

输入单个文件时:

*********************
<WSGIRequest: GET '/home_1b/?fi_file_names=%5Bobject%20File%5D'>
<QueryDict: {'fi_file_names': ['[object File]']}>
[object File]
<MultiValueDict: {}>
*********************
[04/Oct/2023 15:03:50] "GET /home_1b/?fi_file_names=%5Bobject%20File%5D HTTP/1.1" 200 56

输入多个文件时:

*********************
<WSGIRequest: GET '/home_1b/?fi_file_names=%5Bobject%20File%5D&fi_file_names=%5Bobject%20File%5D&fi_file_names=%5Bobject%20File%5D'>
<QueryDict: {'fi_file_names': ['[object File]', '[object File]', '[object File]']}>
[object File]
<MultiValueDict: {}>
*********************
[04/Oct/2023 15:05:26] "GET /home_1b/?fi_file_names=%5Bobject%20File%5D&fi_file_names=%5Bobject%20File%5D&fi_file_names=%5Bobject%20File%5D HTTP/1.1" 200 56
原因分析

你用的是hx-get请求,GET请求会把表单数据拼在URL里,但File对象无法直接转成URL参数,浏览器只能把它转成字符串[object File],所以后端拿到的就是这个无效值。另外,即使设置了hx-encoding="multipart/form-data",GET请求也不支持这种编码方式,只有POST请求才会正确处理multipart数据。

解决方案

方法一:前端用JS提取文件名,再发送请求

不需要上传文件的话,可以直接在前端通过JavaScript获取选中文件的文件名,然后把这些文件名作为普通参数发送给后端。

修改home.html,添加JS处理逻辑:

<!-- templates/home.html -->
{% extends "base.html" %}
{% block head %}
{% load static %}
<script src="{% static '/htmx/htmx.min.js' %}"></script>
<style>
    .column {float:left; width:50%;}
    .row:after{content:""; display:table; clear:both;}
    label {font-family:Verdana; font-size:small;}
    input[type="file"] {width:350px; padding:1px 3px 1px 3px; font-family:Verdana; font-size:small;  border-style:solid; border-width:1px; background-color:lightgray;}
    input[type="file"]::file-selector-button {display:none;}
</style>
<script>
document.getElementById('fi_file_names').addEventListener('change', function(e) {
    // 获取选中的文件名列表
    const fileNames = Array.from(this.files).map(file => file.name);
    // 用htmx发送POST请求,把文件名作为参数传递
    htmx.ajax('POST', "{% url 'home_1b' %}", {
        target: '#home_1b_slot',
        params: { 'fi_file_names': fileNames }
    });
});
</script>
{% endblock head %}
{% block content %}
<h2>File name entry</h2>
<div id="home_r1c1" class="row">
    <h3>Enter the file name(s) to be cited in the report</h3>
    <div id="home_1a_slot">
        <label for="fi_file_names" style="border:1px solid; border-radius:3px; padding:1px 5px 1px 5px; background-color:lightgray;">...</label>
        <input type='file' multiple id="fi_file_names" name="fi_file_names"></input>
    </div>
    <h3>Review the files specified</h3>
    <div id="home_1b_slot">
    </div>
</div>
{% endblock content %}

修改views.py,从POST请求中获取文件名:

def home_1b(request):
    print('*********************')
    print(request)
    # 获取文件名列表,request.POST.getlist会拿到所有同名参数
    file_names = request.POST.getlist('fi_file_names')
    print(file_names)
    print('*********************')
    # 可以把文件名传给模板渲染
    return render(request,'home_1b.html', {'file_names': file_names})

home_1b.html可以这样写来展示文件名:

<ul>
{% for name in file_names %}
    <li>{{ name }}</li>
{% endfor %}
</ul>

方法二:改用POST请求,让Django处理File对象

如果坚持用htmx的自动表单提交,可以把请求改成POST,这样Django能正确解析multipart/form-data,拿到File对象后提取文件名。

修改home.html的htmx属性:

<div id="home_1a_slot" 
hx-post="{% url 'home_1b' %}"  <!-- 把get改成post -->
hx-trigger="change"
hx-encoding="multipart/form-data"
hx-target="#home_1b_slot"
hx-include="#fi_file_names">
    <label for="fi_file_names" style="border:1px solid; border-radius:3px; padding:1px 5px 1px 5px; background-color:lightgray;">...</label>
    <input type='file' multiple id="fi_file_names" name="fi_file_names"></input>
</div>

修改views.py,从request.FILES中获取文件对象,提取文件名:

def home_1b(request):
    print('*********************')
    print(request)
    file_names = []
    # 从FILES中获取所有上传的文件对象
    if 'fi_file_names' in request.FILES:
        for file in request.FILES.getlist('fi_file_names'):
            file_names.append(file.name)
    print(file_names)
    print('*********************')
    return render(request,'home_1b.html', {'file_names': file_names})

同样,home_1b.html可以用循环展示文件名。

内容的提问来源于stack exchange,提问作者JDM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 10:44:56