I am trying to put 2fa in a single page on the registeration View. I was following this advice to put forms inside a single View answer. Code below:
Actually I have two questions:
- While i'm checking the validity of my form
rform.is_valid() -> False
my querydict entries after filling the form are:
<QueryDict: {'csrfmiddlewaretoken': ['b7bAYqqW7IFX93d8U8fsvHeWDvW9fn7HRt8cBcpGx9QHRXDfb1thhH5q2r7W3jmC'], 'register-phone_number_0': ['+224'], 'register-phone_number_1': ['123123123'], 'register-password1': ['Fq7dzcBnkksAVVi'], 'register-password2': ['Fq7dzcBnkksAVVi'], 'register': ['']}>
it returns false, even though I had seperate the two forms.
- While I submit the first form 'rform' I just want it to send a SMS message so I don't want to refresh the page because it erases the password field which already filled. Is there anyway to do this? the return statment
return self.render_to_response({'rform': rform, 'tform': tform})
returns everything filled except the password.
My expected flow is:
User fills phone and pass -> press the send button (POST the number and authentication request via twillio) -> User gets the SMS message -> User fills in the token -> Press the Save button which saves the user instance
Thank you for the answers
form
class RegisterForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Konfirmasi Password', widget=forms.PasswordInput)
class Meta:
model = Account
fields = ('phone_number', )
widgets = {
'phone_number': PhoneNumberPrefixWidget(initial='+62'),
}
labels = {
'phone_number': 'Phone Number',
}
def clean_password2(self):
# Check that two passwords match
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Password don't match")
validate_password(password2)
return password2
def save(self, commit=True):
#saved provided password in hashed format
user = super(RegisterForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
class TokenForm(forms.Form):
token = forms.CharField(
label='Code Konfirmasi', max_length=7, widget=forms.TextInput, required=False)
view
def _get_form(request, formcls, prefix):
data = request.POST if prefix in request.POST else None
return formcls(data, prefix=prefix)
class RegisterView(TemplateView):
template_name = 'authentication/register.html'
def get(self, request, *args, **kwargs):
return self.render_to_response({'rform': RegisterForm(prefix='register'), 'tform': TokenForm(prefix='token')})
def post(self, request, *args, **kwargs):
rform = _get_form(request, RegisterForm, 'register')
tform = _get_form(request, TokenForm, 'token')
print(rform.is_valid())
if rform.is_bound and rform.is_valid():
phone = rform.cleaned_data['phone_number']
elif tform.is_bound and tform.is_valid():
pass
return self.render_to_response({'rform': rform, 'tform': tform})
HTML
<form method='POST'>
{% csrf_token %}
{{ rform.phone_number|as_crispy_field }}
<div class="row">
<div class="col-6">
{{ rform.password1|as_crispy_field }}
</div>
<div class="col-6">
{{ rform.password2|as_crispy_field }}
</div>
</div>
<div class="row align-items-center">
<div class="col">
<button type='submit' name="{{rform.prefix}}" class='btn btn-success'>Send Code</button>
</div>
</div>
</form>
<form>
<div class="col-3">
{{ tform.token|as_crispy_field }}
</div>
<button type='submit' name="{{tform.prefix}}" id="submit_register" class='btn btn-success'>Submit</button>
</form>