django 一次性上传多个文件, 批量上传

文章详细解释了使用Django进行文件上传时,如何正确处理前端HTML5多文件选择功能,以及如何从request.FILES中获取所有上传的文件。通过实例展示了如何使用request.FILES.getlist方法来解决只获取最后一个文件的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在用django 写文件上传的时候,从request.FILES['myfiles'] 获取到的文件始终只有一个, 但在HTML页面上明明用 HTML5 的 文件控件选择了多个文件,用的是CHROME  浏览器,一次可以选择多个文件上传。在 Pydev 开启debug模式,查看request 对象,发现上传的多个文件确实在request对象中,但为什么 用request.FILES['myfiles'] 却只能得到一个呢?

前端 html5 上传控件, 我用了jquery file upload 
<span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="tag" style="font-family:Arial,宋体;font-size:12px;color:#8000;"><input</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="atn" style="font-family:Arial,宋体;font-size:12px;color:#ff00;">type</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">=</span><span class="atv" style="font-family:Arial,宋体;font-size:12px;color:#00ff;">"file"</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="atn" style="font-family:Arial,宋体;font-size:12px;color:#ff00;">name</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">=</span><span class="atv" style="font-family:Arial,宋体;font-size:12px;color:#00ff;">"myfiles"</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="atn" style="font-family:Arial,宋体;font-size:12px;color:#ff00;">multiple</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">=</span><span class="atv" style="font-family:Arial,宋体;font-size:12px;color:#00ff;">""</span><span class="tag" style="font-family:Arial,宋体;font-size:12px;color:#8000;">></span>




选择多个文件之后, 然后提交请求,开启pydev debug 模式,查看request内容:


其中request.FILES 的内容为如下:
<span class="typ" style="font-family:Arial,宋体;font-size:12px;color:#2b91af;">MultiValueDict</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">:</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;"><</span><span class="typ" style="font-family:Arial,宋体;font-size:12px;color:#2b91af;">MultiValueDict</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">:</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">{</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">u</span><span class="str" style="font-family:Arial,宋体;font-size:12px;color:#8000;">'myfiles'</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">:</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">[<</span><span class="typ" style="font-family:Arial,宋体;font-size:12px;color:#2b91af;">InMemoryUploadedFile</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">:</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="lit" style="font-family:Arial,宋体;font-size:12px;color:#8000;">300x600.png</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">(</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">image</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">/</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">png</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">)>,</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;"><</span><span class="typ" style="font-family:Arial,宋体;font-size:12px;color:#2b91af;">InMemoryUploadedFile</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">:</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> todo</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">.</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">txt </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">(</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">text</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">/</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">plain</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">)>]}></span>


很明显,上传的文件的确在其中,但是当用 request.FILES['myfiles'] 得到的确是最后一个。 而不能得到两个文件。跟踪代码发现,request.FILES 的类型为 MultiValueDict,这种字典类是特殊定义的,如果需要取得list 需要调用 getlist  方法,看到这里,豁然开朗,下面是得到上传的多个文件与处理的逻辑

<span class="pln" style="font-family:Arial,宋体;font-size:12px;">files </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">=</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> request</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">.</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">FILES</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">.</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">getlist</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">(</span><span class="str" style="font-family:Arial,宋体;font-size:12px;color:#8000;">'myfiles'</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">)</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">
</span><span class="kwd" style="font-family:Arial,宋体;font-size:12px;color:#008b;">for</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> f </span><span class="kwd" style="font-family:Arial,宋体;font-size:12px;color:#008b;">in</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> files</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">:</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">      
     destination </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">=</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> open</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">(</span><span class="str" style="font-family:Arial,宋体;font-size:12px;color:#8000;">'d:/temp/'</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> </span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">+</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> f</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">.</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">name</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">,</span><span class="str" style="font-family:Arial,宋体;font-size:12px;color:#8000;">'wb+'</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">)</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">
     </span><span class="kwd" style="font-family:Arial,宋体;font-size:12px;color:#008b;">for</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> chunk </span><span class="kwd" style="font-family:Arial,宋体;font-size:12px;color:#008b;">in</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> f</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">.</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">chunks</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">():</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;"> 
          destination</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">.</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">write</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">(</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">chunk</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">)</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">
     destination</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">.</span><span class="pln" style="font-family:Arial,宋体;font-size:12px;">close</span><span class="pun" style="font-family:Arial,宋体;font-size:12px;">()</span>


其实很简单的,就是不细心,另外django 默认是只处理单个文件上传的,要一次性批量处理多个文件上传就得采用这种方法。
<think>我们被要求一次性设置多个外键字段的值。在Django中,外键字段实际上存储的是关联对象的主键值。因此,设置外键字段的值实际上就是设置关联对象的主键(即id)。 根据引用[1]:Django约定在外键字段名后附加“_id”。例如,如果有一个外键字段`reporter`,那么实际存储外键的数据库字段名为`reporter_id`。我们可以直接设置这个`字段名_id`来指定关联对象的主键。 因此,如果我们想一次性设置多个外键字段的值,我们可以直接为这些外键字段对应的数据库列(即`字段名_id`)赋值。这可以通过以下方式实现: 1. 使用`update()`方法:如果我们已经有一个查询集(QuerySet),并且想批量更新多个对象的外键字段,我们可以使用`update()`方法,直接设置`外键字段_id`为指定的值(即关联对象的主键)。 2. 在创建对象时,我们可以直接传递`外键字段_id`参数。 注意:直接设置`_id`字段是直接操作数据库列,避免了先获取关联对象的开销,因此效率较高。 示例: 假设我们有两个模型:`Reporter`(记者)和`Article`(文章),其中`Article`有一个外键指向`Reporter`(如引用[2]所示)。 我们想要一次性多个文章的`reporter`外键设置为同一个记者(假设该记者的id为1)。 我们可以这样做: ```python # 批量更新:将所有文章的reporter_id设置为1 Article.objects.all().update(reporter_id=1) ``` 如果我们想要为不同的文章设置不同的记者id,我们可以结合条件更新,或者使用批量更新操作(但注意,update一次只能设置一个值,所以如果要设置不同的值,需要分别更新)。 但是,如果我们有多个外键字段需要设置,比如一个模型有两个外键字段`author`和`editor`,我们想同时设置这两个外键,可以这样: ```python # 假设我们有一个特定的文章对象 article = Article.objects.get(id=1) # 同时设置两个外键的id article.author_id = 2 article.editor_id = 3 article.save() ``` 或者批量更新多个对象: ```python # 更新所有文章的author_id为2,editor_id为3 Article.objects.all().update(author_id=2, editor_id=3) ``` 注意:`update()`是直接在数据库层面执行更新操作,不会调用模型的`save()`方法,也不会触发信号(signals)。 另外,如果我们已经有关联对象实例,也可以直接传递对象本身,但是这样需要先获取对象,然后赋值给外键字段(而不是`_id`字段)。例如: ```python reporter = Reporter.objects.get(id=1) article.reporter = reporter ``` 但这种方式在批量更新时效率较低,因为需要先获取每个关联对象。而直接设置`_id`则避免了这一步。 总结: 一次性设置多个外键字段的值,可以通过直接设置这些外键字段对应的`_id`字段(数据库列)来实现。在批量更新时,使用`update()`方法并传递多个`字段名_id=值`参数即可。 引用说明: - 引用[1]告诉我们外键字段在数据库中的实际列名是字段名加上“_id”,因此我们可以直接操作这个列名。</think>在 Django一次性设置多个外键字段的值,可以通过以下高效方法实现: ### 推荐方法:直接设置 `_id` 后缀字段 根据引用[1],Django 会自动为外键字段添加 `_id` 后缀(如 `reporter_id`)。这是最高效的方法: ```python # 假设 Article 模型有 reporter 和 editor 两个外键 article = Article.objects.get(id=1) # 一次性设置两个外键的值(使用主键ID) article.reporter_id = 5 # 直接设置 reporter_id article.editor_id = 8 # 直接设置 editor_id article.save() ``` **优点**: - 避免数据库额外查询(不需要先获取对象实例) - 减少数据库交互次数 - 支持批量操作 ### 批量更新多个对象的外键 使用 `update()` 方法实现高效批量更新: ```python # 将特定文章集合的 reporter 和 editor 同时更新 Article.objects.filter( pub_date__year=2023 ).update( reporter_id=10, # 设置 reporter 外键 editor_id=15 # 设置 editor 外键 ) ``` **性能优势**: - 单条 SQL 语句完成所有更新 - 不加载模型实例,内存效率高 - 避免 N+1 查询问题 ### 创建对象时批量设置外键 在创建新对象时直接指定外键值: ```python # 创建新文章时直接设置外键ID new_article = Article.objects.create( headline="Breaking News", pub_date=date.today(), reporter_id=3, # 直接使用ID值 editor_id=7, # 直接使用ID值 content="..." ) ``` ### 使用 `bulk_update()` 批量操作 Django 3.0+ 支持的高效批量更新方法: ```python articles = Article.objects.filter(category='tech')[:100] # 批量修改外键值 for article in articles: article.reporter_id = 20 article.editor_id = 25 # 单次数据库提交完成所有更新 Article.objects.bulk_update(articles, ['reporter_id', 'editor_id']) ``` ### 为什么不推荐使用完整对象实例? ```python # 低效方法(需要额外查询) reporter = Reporter.objects.get(id=5) editor = Editor.objects.get(id=8) article.reporter = reporter # 需要先查询对象 article.editor = editor # 需要先查询对象 article.save() ``` **缺点**: - 产生额外数据库查询 - 增加网络往返开销 - 内存占用更高(需加载完整对象) ### 关键点总结 1. **始终使用 `_id` 后缀**:直接操作数据库外键列(引用[1]) 2. **批量操作优先**:使用 `update()` 或 `bulk_update()` 减少数据库交互 3. **避免对象实例化**:除非需要验证或信号处理,否则直接用ID 4. **事务保护**:对关键操作使用 `transaction.atomic()` > 通过直接操作 `字段名_id`,您可以绕过 Django 的 ORM 对象实例化过程,实现接近原生 SQL 的性能[^1][^4]。这种方法特别适合需要高性能处理的场景,如数据迁移或批量导入。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值