You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:26:18