Django 保存表单未完成进度

11 投票
3 回答
4837 浏览
提问于 2025-04-16 06:59

我有一个用Django做的网页应用,很多用户可以登录并填写表单。

有些用户在填写表单的时候,可能会缺少一些必要的信息(比如说,申请号),这些信息是验证表单所需要的(在我们开始处理之前)。我希望他们可以填写表单,并且有一个选项可以保存部分信息(这样他们可以在其他时间重新登录来完成表单),或者提交完整的信息进行验证。

目前我使用ModelForm来处理所有的表单,而模型中有一些限制来确保数据的有效性(比如,申请号必须是唯一的)。但是,我希望他们能够保存这些中间数据,而不需要进行任何验证。

我想到的解决方案似乎有点笨拙,也不太符合Django的风格:创建一个“保存部分表单”的按钮,保存POST字典并将其转换为一个shelf文件,同时创建一个“SavedPartialForm”模型,将用户和保存在shelf中的部分表单连接起来。这样做合理吗?有没有更好的方法可以直接把POST字典保存到数据库中?或者有没有什么附加模块可以实现表单的部分保存(这在网页表单中似乎是个比较常见的需求)?

我最担心的是,我希望最终能够实现自动保存表单的功能(比如每10分钟自动保存一次),用某种ajax/jquery的方法,而不需要实际按按钮发送POST请求(例如,这样用户在自动保存时不会被重定向到其他页面)。我对jquery不太熟悉,想知道这样做是否可行。

3 个回答

1

把下面的内容放到你的表单的 __init__ 方法里

for field in form.fields:
    form.fields[field].required = False

举个例子:

class MySexyForm(Form):
    def __init__(self, *args, **kwargs):
        super(MySexyForm, self).__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].required = False

然后调用:

form = MySexyForm(...)
form.save()

不过,你需要确保你的 clean() 方法能够处理缺失的属性,方法是检查这些属性是否存在于 cleaned_data 中。比如说,如果另一个表单字段的验证依赖于 customer_id,但你的表单没有指定这个值,那么 customer_id 就不会出现在 cleaned_data 里。

如果这是一个模型表单,你可以检查这个值是否在 cleaned_data 中,如果缺失了,就可以使用 instance.field 作为备用,比如:

def clean(self):
    inst = self.instance
    customer_id_new = self.cleaned_data.get('customer_id', None)
    customer_id_old = getattr(self.instance, 'customer_id') if inst else None
    customer_id = customer_id_new if customer_id_new else customer_id_old

记住,新值的格式几乎肯定和旧值不一样,比如 customer_id 在模型实例中可能是一个 RelatedField,但在表单数据中却是一个主键 int。所以,你需要在 clean 方法里处理这些类型的差异。

可惜的是,这正是 Django 表单的一个不足之处。

1

问题在于你有多个表单。

有部分的、不完整的、完整的,还有准备好的和待处理的。

实际上,你是为工作流程的每个阶段准备了一个表单。

这样做没有任何问题。

  1. 先弄清楚你在工作流程的哪个阶段。

  2. 填写并展示下一个阶段的表单。

表单之间可以相互继承,这样就可以避免重复验证的方法。

3

在保存之前:

for field in form.fields:
    form.fields[field].required = False

然后:

form.save()

撰写回答