如何构建一个需要延迟重新提交的Django表单?

0 投票
2 回答
765 浏览
提问于 2025-04-15 22:26

为了避免垃圾信息,我想给表单重新提交加个等待时间(也就是说,用户在提交表单后需要等几秒钟才能再次提交,除了第一次提交表单的时候)。

为此,我在我的表单中添加了一个 timestamp(时间戳),还加了一个 security_hash 字段,这个字段包含时间戳和 settings.SECRET_KEY,这样可以确保时间戳不会被篡改。这个看起来像这样:

class MyForm(forms.Form):
    timestamp     = forms.IntegerField(widget=forms.HiddenInput)
    security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput)
    # + some other fields..

    # + methods to build the hash and to clean the timestamp...
    # (it is based on django.contrib.comments.forms.CommentSecurityForm)

    def clean_timestamp(self):
        """Make sure the delay is over (5 seconds)."""
        ts = self.cleaned_data["timestamp"]
        if not time.time() - ts > 5:
            raise forms.ValidationError("Timestamp check failed")
        return ts

    # etc...

这样做是有效的。但是还有一个问题:用户第一次提交表单时会检查时间戳,我需要避免这个检查

有什么办法可以解决这个问题吗?

谢谢!:-)

2 个回答

2

时间戳是在用户第一次提交表单时被检查的,我需要避免这种情况。

如果这是问题的话,难道你不能在创建表单的时候把时间戳设置为提前5分钟吗?

2

一种方法是给时间设置一个初始值,比如说0,然后在表单验证通过后把这个值更新为当前的时间戳。之后只有在这个时间戳不是0的时候才进行检查:

class MyForm(forms.Form):
    timestamp     = forms.IntegerField(widget=forms.HiddenInput, initial=0)
    #look at the initial = 0

    security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput)


    def clean_timestamp(self):
        """Make sure the delay is over (5 seconds)."""
        ts = self.cleaned_data["timestamp"]
        if timestamp != 0 and not time.time() - ts > 5:
            raise forms.ValidationError("Timestamp check failed")
        return ts

    def clean(self):
        cleaned_data = self.cleaned_data
        if len(self._errors) == 0: #it validates
            cleaned_data["timestamp"] = time.time()
        return cleaned_data

另一种可能的解决方案是使用会话(sessions)。这种方法更安全,但也不是绝对可靠。使用前面提到的方法,用户可以多次发送相同的表单数据,因为他发送的时间戳是一样的,表单就会多次通过验证。而使用会话的话,用户需要开启浏览器的cookies,但他们发送的表单数据不会在5秒内通过验证。

这样一来,一旦用户正确提交了表单,你就可以把时间保存在用户的会话中,并在重新验证表单之前进行检查。这在视图中很容易实现。如果你想在表单逻辑层面上处理,就需要在表单中创建自己的清理方法,这样才能使用会话。要小心,用户可以清除他的cookies,然后以“新用户”的身份重新提交。

希望这些信息对你有帮助。

撰写回答