django 将参数从视图传递到表单仅一次

django pass argument from view to form only once

我有一个 OTP 生成器机制,在 GET 方法中,生成一个唯一的 4 位 OTP 并发送到 OTPAuthenticationForm(),如下所示:

views.py

if request.method == 'GET':
   otp = 'abcd'
   # code to send otp via mail
   form = OTPAuthenticationForm(request=request, otp=otp) # this is how the OTP is passed only once.
   return ....
elif request.method == 'POST':
    form = OTPAuthenticationForm(request.POST, request=request)
    if form.is_valid():                 # the clean_field() method is not invoked/throws error.
       print("OTP is valid")
    else: 
       print("OTP is invalid")

forms.py

from django.contrib.auth.forms import AuthenticationForm


class OTPAuthenticationForm(AuthenticationForm):
    otp = forms.CharField(required=True, widget=forms.TextInput)

    def __init__(self, otp, *args, **kwargs):
       self.otp = kwargs.pop("otp")

       super(OTPAuthenticationForm, self).__init__(*args, **kwargs)

    def clean(self):
       if self.otp!= self.cleaned_data['otp']:
          raise forms.ValidationError("Invalid OTP")

如何将 generated_otp 仅传递给 OTPAuthForm() 一次,以便根据用户输入的 OTP(通过电子邮件收到的 OTP)对其进行验证。

未调用 clean() 方法;而不是在执行 form.is_valid() 时,形式 return 'invalid' error

更新:OTPAuthenticationForm(forms.Form) 之前导入了 class AuthenticationForm(),它需要用户名、密码字段以及自定义 OTP场地。

这就是 form.is_valid() return 无效的原因,因为用户名、密码 auth 在应用程序中单独处理。

我认为你不应该在 GET 请求中传递 otp,而应该由 POST 请求完成:

form = OTPAuthenticationForm(request.POST, request=request, otp=otp)

同时更新表格:

class OTPAuthenticationForm(AuthenticationForm):
    otp = forms.CharField(required=True, widget=forms.TextInput)

    def __init__(self, otp, *args, **kwargs):
       self.otp_value = kwargs.pop("otp", None)
       super(OTPAuthenticationForm, self).__init__(*args, **kwargs)

    def clean(self):
       otp = self.cleaned_data['otp']
       if self.otp_value != otp:
          raise forms.ValidationError("Invalid OTP")
       return super(OTPAuthenticationForm, self).clean()

现在,问题是当您收到 POST 请求时如何存储该 OTP。你可以使用会话。像这样:

if request.method == 'GET':
   otp = 'abcd'
   form = OTPAuthenticationForm(request=request)
   request.session['otp'] = otp  # storing data in session
   return ....
elif request.method == 'POST':
    form = OTPAuthenticationForm(request.POST, request=request, otp=request.session.get('otp'))
    if form.is_valid():
        del request.session['otp'] # deleting data in session
        ...