Django存储文件删除功能在IIS失效,本地运行正常
问题
我开发了一个用于删除用户选定文件的Django模块,在确认用户的删除意愿后,编写了如下views.py代码:
@login_required(login_url='/login/') def Delete_files(request, pk): # Get the RadioFile object based on the primary key (pk) radio_file = get_object_or_404(RadioFile, pk=pk) print(radio_file) # get the file path and file object from the database file_obj = RadioFile.objects.get(id=pk).audio_file radio = radio_file.audio_file file_path = file_obj.path print(file_path) # Check that the user is the owner of the file if request.user != radio_file.uploaded_by: messages.success(request, 'File can be deleted by its owner.') # store the message in a message queue return redirect('/') elif os.path.exists(file_path) and not os.path.isfile(file_path): print(f"Error: {file_path} is not a file") response_data = {'success': False, 'error': str(e)} else: try : with transaction.atomic(): # Remove the many-to-many relationship with categories radio_file.categories.clear() radio_file.share_with.clear() # Delete the Radio object radio_file.delete() # Delete the file from the filesystem radio.close() radio.delete() messages.success(request, 'Radio and file deleted successfully.') response_data = {'success': True} except Exception as e: print(str(e)) messages.error(request, 'some error is coming while deleteing file.') # Redirect to the file list view return redirect('/')
上述代码在本地环境运行时可正常删除文件,但部署到IIS服务器时出现Win32权限错误,提示文件已被其他程序占用,而该文件仅被Python用于向用户展示文件列表。请协助排查并解决该问题。
排查与解决方案
1. 修复重复查询导致的未关闭文件句柄
代码中重复查询RadioFile对象(get_object_or_404后又调用RadioFile.objects.get),会生成多个文件实例,每个实例都可能持有未释放的文件句柄。Windows系统对文件句柄的锁定机制比Linux严格,未关闭的句柄会导致文件无法删除。
修改文件路径获取逻辑,去掉重复查询,仅使用已获取的radio_file对象:
# 替换原文件路径获取代码,避免持有多余的文件对象 file_path = radio_file.audio_file.path
2. 调整事务与文件删除的顺序
当前在事务块内先删除数据库对象再删除文件,事务未提交时,Django可能仍持有文件句柄。Windows下数据库对象未被完全垃圾回收时,句柄不会释放,导致删除失败。
将文件删除操作移出事务块,确保数据库记录删除完成后再处理文件:
try : with transaction.atomic(): radio_file.categories.clear() radio_file.share_with.clear() # 先提交数据库删除操作 radio_file.delete() # 事务提交后,确认文件存在再删除 if os.path.exists(file_path): # 显式打开并关闭文件,强制释放可能存在的句柄 with open(file_path, 'rb'): pass os.remove(file_path) messages.success(request, 'Radio and file deleted successfully.') except Exception as e: print(str(e)) messages.error(request, '删除文件时发生错误。') return redirect('/')
3. 检查IIS应用池权限与缓存
- 权限配置:确保IIS应用池的运行账户(如
IIS AppPool\你的应用池名称)对文件存储目录拥有读取、写入、删除权限。Windows下需直接给应用池账户分配权限,不要依赖继承。 - 禁用静态文件缓存:如果文件通过静态URL访问,IIS的静态文件模块可能缓存文件句柄。在项目根目录的
Web.config中添加以下配置,禁用目标目录的缓存:
<location path="音频文件存储目录"> <system.webServer> <staticContent> <clientCache cacheControlMode="DisableCache" /> </staticContent> </system.webServer> </location>
4. 替换Django的File.delete()方法
Django的FileField.delete()在Windows环境下可能存在句柄泄漏问题,建议直接使用Python标准库的os.remove()删除文件,确保所有句柄已释放后再执行删除操作。
内容的提问来源于stack exchange,提问作者PTB
相关产品推荐
相关产品推荐

