Django多视图拆分ModelForm并实现登录用户进度保存需求
多页面ModelForm的进度保存解决方案(针对登录用户)
Hey! 针对你要把Django的JobApplication ModelForm拆分成多页面、让登录用户能随时保存进度不用提交完整内容的需求,除了缓存,这里有几个更可靠的方案,都是我在实际项目里用过或者验证过的:
方案一:数据库草稿模型(最推荐,持久化且可追溯)
缓存的问题在于数据可能因为过期、缓存清理丢失,而用数据库存草稿是最稳妥的方式,还能支持后续查看、编辑历史。
步骤1:创建草稿模型
首先定义一个和JobApplication关联的草稿模型,用来存储用户未完成的表单数据:
from django.db import models from django.contrib.auth.models import User from .models import JobApplication class JobApplicationDraft(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='job_drafts') job_application = models.ForeignKey(JobApplication, on_delete=models.SET_NULL, null=True, blank=True) # 用JSONField存储表单数据,兼容不同字段类型 form_data = models.JSONField(default=dict) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = "职位申请草稿"
步骤2:拆分表单并处理草稿保存
把原来的JobApplicationForm拆分成多个子表单,比如JobApplicationStep1Form、JobApplicationStep2Form,每个表单只包含对应页面的字段。
在视图里,用户每次提交当前页面的表单时(不管是否完成全部步骤),先验证当前页面的字段(只验证当前表单的字段,不用全量验证),然后保存到草稿:
from django.shortcuts import render, redirect from .forms import JobApplicationStep1Form, JobApplicationStep2Form from .models import JobApplicationDraft def step1_view(request): # 尝试获取用户已有的草稿 draft = JobApplicationDraft.objects.filter(user=request.user).first() initial_data = draft.form_data if draft else {} if request.method == 'POST': form = JobApplicationStep1Form(request.POST, initial=initial_data) if form.is_valid(): # 合并当前步骤的数据到草稿 updated_data = {**initial_data, **form.cleaned_data} if draft: draft.form_data = updated_data draft.save() else: JobApplicationDraft.objects.create(user=request.user, form_data=updated_data) # 跳转到下一页 return redirect('step2') else: form = JobApplicationStep1Form(initial=initial_data) return render(request, 'step1.html', {'form': form})
步骤3:完成所有步骤后同步到正式模型
当用户提交最后一步表单时,把草稿里的所有数据同步到JobApplication,并可以删除草稿(或者保留作为历史):
def final_step_view(request): draft = JobApplicationDraft.objects.filter(user=request.user).first() if not draft: return redirect('step1') initial_data = draft.form_data if request.method == 'POST': form = JobApplicationFinalForm(request.POST, initial=initial_data) if form.is_valid(): # 创建正式的JobApplication实例 job_app = JobApplication.objects.create( user=request.user, **{**initial_data, **form.cleaned_data} ) # 关联草稿到正式实例(可选) draft.job_application = job_app draft.save() # 或者删除草稿 # draft.delete() return redirect('success') else: form = JobApplicationFinalForm(initial=initial_data) return render(request, 'final_step.html', {'form': form})
方案二:使用Django FormTools的FormWizard(快速搭建)
如果你不想自己写太多草稿逻辑,可以用django-formtools的FormWizard组件,它自带进度保存功能,还能支持Session或数据库存储进度。
安装和配置
先安装:
pip install django-formtools
然后把formtools加到INSTALLED_APPS里。
实现带草稿保存的Wizard
继承SessionWizardView,并结合用户模型实现草稿持久化:
from formtools.wizard.views import SessionWizardView from .forms import JobApplicationStep1Form, JobApplicationStep2Form, JobApplicationFinalForm from .models import JobApplicationDraft FORMS = [ ('step1', JobApplicationStep1Form), ('step2', JobApplicationStep2Form), ('final', JobApplicationFinalForm), ] TEMPLATES = { 'step1': 'step1.html', 'step2': 'step2.html', 'final': 'final_step.html', } class JobApplicationWizard(SessionWizardView): form_list = FORMS template_name = 'wizard_base.html' def get_template_names(self): return [TEMPLATES[self.steps.current]] def dispatch(self, request, *args, **kwargs): # 加载用户已有的草稿到Session draft = JobApplicationDraft.objects.filter(user=request.user).first() if draft and not self.storage.data: self.storage.data = draft.form_data return super().dispatch(request, *args, **kwargs) def process_step(self, form): # 每一步提交后保存到草稿 draft, created = JobApplicationDraft.objects.get_or_create(user=self.request.user) draft.form_data = {**draft.form_data, **form.cleaned_data} draft.save() return super().process_step(form) def done(self, form_list, **kwargs): # 所有步骤完成后创建正式实例 form_data = {} for form in form_list: form_data.update(form.cleaned_data) job_app = JobApplication.objects.create(user=self.request.user, **form_data) # 关联草稿并清除Session数据 draft = JobApplicationDraft.objects.get(user=self.request.user) draft.job_application = job_app draft.save() self.storage.reset() return redirect('success')
方案对比
- 数据库草稿模型:最灵活,支持数据持久化、历史追溯,适合需要对草稿进行管理(比如查看用户未完成的申请)的场景,代码量稍大但可控。
- FormWizard:快速搭建多页表单,自带步骤管理,适合不需要复杂草稿逻辑的场景,减少重复代码。
- 缓存方案:适合临时存储,但不推荐作为唯一方案,可配合数据库方案做缓存加速(比如把草稿数据缓存起来,减少数据库查询)。
内容的提问来源于stack exchange,提问作者jayt
相关产品推荐
相关产品推荐

