Django多文件上传报错:'list' object has no attribute '_committed'
报错原因分析
- 模型与表单字段不匹配:
LevelType模型里的images是单个FileField(仅支持单文件存储),但自定义的MultipleFileField返回的是文件列表。执行form.save()时,Django尝试把列表赋值给仅能存储单个文件的字段,触发'list' object has no attribute '_committed'错误——因为单文件字段期望的是UploadedFile对象,而非列表。 - 视图逻辑存在多处问题:
- 先调用
form.save()会直接触发字段不匹配的报错; - 循环里的字段名写错:模型字段是
images,代码里写的是image; - 循环内的
return redirect会导致仅处理第一张图片就跳转,后续图片无法保存。
- 先调用
解决办法
第一步:重构模型(核心修正)
单个LevelType对应多张图片,标准方案是用一对多关联,新建图片模型:
from django.conf import settings from django.db import models class LevelType(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) level = models.ForeignKey(Level, on_delete=models.CASCADE) bank_name = models.CharField(max_length=255) account_number = models.CharField(max_length=255) account_name = models.CharField(max_length=255) price = models.DecimalField(max_digits=10, decimal_places=2) currency = models.CharField(max_length=10) description = models.TextField() accept_payment_with_card = models.BooleanField(default=False) class LevelImage(models.Model): level_type = models.ForeignKey(LevelType, on_delete=models.CASCADE, related_name='images') image = models.FileField(upload_to='images-level')
第二步:简化表单实现
无需自定义MultipleFileField,直接用原生字段搭配多文件选择组件:
from django import forms from .models import LevelType class MultipleFileInput(forms.ClearableFileInput): allow_multiple_selected = True class LevelTypesForms(forms.ModelForm): images = forms.FileField(widget=MultipleFileInput()) class Meta: model = LevelType fields = [ 'level', 'bank_name', 'account_number', 'account_name', 'price', 'currency', 'description', 'accept_payment_with_card', ]
第三步:修正视图逻辑
先保存主实例,再批量创建关联图片,避免提前触发字段错误:
from django.views.generic.edit import CreateView from django.urls import reverse_lazy from .models import LevelType, LevelImage from .forms import LevelTypesForms class CreateLevelType(CreateView): model = LevelType form_class = LevelTypesForms success_url = reverse_lazy('Level-Types') template_name = 'Account/create_level_type.html' def get_form(self, form_class=None): form = super().get_form(form_class) form.fields['level'].queryset = Level.objects.filter(user=self.request.user) return form def form_valid(self, form): # 创建主实例但暂不保存到数据库 level_type = form.save(commit=False) level_type.user = self.request.user level_type.save() # 批量处理上传的多张图片 images = self.request.FILES.getlist('images') for image in images: LevelImage.objects.create( level_type=level_type, image=image ) return super().form_valid(form)
额外注意事项
- 表单标签必须添加
enctype="multipart/form-data",否则无法接收上传文件:
<form method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <button type="submit">提交</button> </form>
- 不建议用
JSONField存储文件路径列表的方式实现多文件上传,这种方式无法利用Django的文件管理系统,后续维护成本高。
内容的提问来源于stack exchange,提问作者Adamu Abdulkarim Dee
相关产品推荐
相关产品推荐

