Django Form Wizard 首步FileField提交后数据库为空如何解决
问题根因
你遇到的文件字段为空问题核心有3个错误点:
- 全局变量存表单数据逻辑错误:你自定义的全局
form_data2仅收集了普通POST表单字段,文件属于request.FILES范畴的二进制数据,不会出现在get_form_step_data()返回的普通字段中,所以form_data2里根本不存在file键值对,入库时自然没有值。 - 跳转步骤的文件存储逻辑错误:
render_goto_step方法中你硬编码将当前步骤的文件覆盖存储到第一步的文件槽位,若用户跳转过步骤会导致第一步上传的文件被清空。 - 多线程安全问题:Django服务是多线程运行的,全局变量
form_data、form_data2会在多个用户同时提交时串数据,属于严重的逻辑漏洞。
修复方案
1. 修正跳转步骤的文件存储逻辑
修改render_goto_step方法,将文件存储到当前步骤对应的槽位:
def render_goto_step(self, *args, **kwargs): form = self.get_form(data=self.request.POST, files=self.request.FILES) self.storage.set_step_data(self.steps.current, self.process_step(form)) # 原逻辑错误:把所有步骤的文件都存到第一步,改为存到当前步骤 self.storage.set_step_files(self.steps.current, self.process_step_files(form)) return super().render_goto_step(*args, **kwargs)
2. 重写done方法,废弃全局变量
不要手动拼接表单数据,直接从form_list中取每一步的cleaned数据,文件字段直接从第一步的CompanyForm中获取:
def done(self, form_list, **kwargs): try: # 第一步就是CompanyForm,直接取cleaned_data company_data = form_list[0].cleaned_data address_data = form_list[1].cleaned_data payment_data = form_list[4].cleaned_data # 合并基础数据 customer_data = {**company_data, **address_data, **payment_data} # 处理发票地址逻辑 if not customer_data.get('different_invoice_address'): customer_data['invoice_street'] = customer_data.get('delivery_street') customer_data['invoice_zip'] = customer_data.get('delivery_zip') customer_data['invoice_city'] = customer_data.get('delivery_city') customer_data['invoice_house_number'] = customer_data.get('delivery_number') # 移除不需要的字段 for remove_key in ['csrfmiddlewaretoken', 'register_wizard-current_step', 'wizard_goto_step', 'toa', 'using_mail_address', 'different_invoice_address']: if remove_key in customer_data: customer_data.pop(remove_key) # 直接创建Customer,file字段会自动从company_data中读取并保存到正式路径 customer = Customer.objects.create(**customer_data) # 保存关联表单集 for reference in form_list[2].save(commit=False): reference.customer = customer reference.save() for contact in form_list[3].save(commit=False): contact.customer = customer contact.save() except Exception as e: logger.error(e) finally: return HttpResponseRedirect('/thank-you')
3. 清理冗余代码
删除全局的form_data、form_data2变量,以及process_step方法中操作这两个全局变量的逻辑,你不需要手动收集表单数据,formtools的wizard已经帮你把所有步骤的表单数据、文件都存在storage里了。
内容的提问来源于stack exchange,提问作者Samoht
相关产品推荐
相关产品推荐

