Как создать форму Django, для которой требуется повторная отправка? - PullRequest
0 голосов
/ 07 мая 2010

Чтобы избежать спама, я хотел бы добавить время ожидания для повторной отправки формы (т. Е. Пользователь должен подождать несколько секунд, чтобы отправить форму, , за исключением случаев, когда эта форма отправляется впервые ).

Для этого я добавил 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 голосов
/ 07 мая 2010

Один из способов сделать это - установить начальное значение времени, скажем, 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

Другим возможным решением является использование сессий . Это безопаснее, но не пуленепробиваемый. В предыдущем приложении пользователь может отправлять одни и те же данные сообщения несколько раз, и форма будет проверяться несколько раз (поскольку он отправляет одну и ту же метку времени). В сеансах необходимо, чтобы у пользователя были включены файлы cookie, но он не сможет отправлять данные публикации, которые проверяются быстрее, чем через 5 секунд.

Таким образом, после правильной отправки формы вы можете сэкономить время в ключе сеанса пользователя и проверить его перед повторной проверкой формы. Это легко сделать в представлении. Если вы хотите сделать это на уровне логики формы, вам нужно создать собственный чистый метод в форме, которая принимает запрос (чтобы вы могли использовать сеанс). Будьте внимательны, пользователь может чистить свои куки и публиковать их как «нового» пользователя.

Надеюсь, это поможет.

2 голосов
/ 07 мая 2010

отметка времени проверяется при первой отправке формы пользователем, и мне нужно этого избегать.

Если это проблема, не могли бы вы создать форму с установкой метки времени -5 минут?

...