Issues with two forms submission in django one after another - django

I'm working on forget password page in which the user first have to answer the question for enabling the textfields for creating new password.
Here, I have two forms, One for security question and second for password and confirm password.
Following is my forms.py
from django import forms
from .models import SecurityQuestions
class PasswordForm(forms.Form):
password = forms.CharField(disabled=True, widget=forms.PasswordInput(attrs={'placeholder':'New Password'}))
password_confirm = forms.CharField(disabled=True, widget=forms.PasswordInput(attrs={'placeholder':'Re-enter Password'}))
def clean(self, *args,**kwargs):
password = self.cleaned_data.get('password')
password_confirm = self.cleaned_data.get('password_confirm')
if password and password_confirm:
if password != password_confirm:
raise forms.ValidationError('Password Mismatch')
return super(PasswordForm, self).clean(*args, **kwargs)
class PasswordVerificationForm(forms.Form):
question = forms.ModelChoiceField(queryset=SecurityQuestions.objects.all(), empty_label=None, widget=forms.Select(attrs={'class':'form-control','id': 'sectxt'}))
answer = forms.CharField(label='answer', widget=forms.TextInput(attrs={'placeholder':'Answer','id': 'anstxt'}))
Following is my views.py
from django.shortcuts import render, redirect
from .forms import PasswordForm, PasswordVerificationForm
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.hashers import make_password
from .models import SecurityQuestions
from django.contrib import messages
#login_required
#csrf_exempt
def password_reset(request):
form = PasswordForm(request.POST or None)
form1 = PasswordVerificationForm(request.POST or None)
if request.method == 'POST':
if request.POST.get("verify", False):
question = request.POST.get('question')
answer = request.POST.get('answer')
print("question",question)
print("answer",answer)
check = SecurityQuestions.objects.get(id=question) #id=1
print(check.answer)
if check.answer == answer:
messages.success(request, 'Enter Your New Password', 'alert-success')
form.fields['password'].disabled = False
form.fields['password_confirm'].disabled = False
else:
redirect('/')
messages.error(request, 'Incorrect Answer', 'alert-danger')
if request.POST.get("create", False):
if form.is_valid():
print("For Changing Password...")
password = form.cleaned_data.get('password')
request.user.password = make_password(password)
request.user.save()
return redirect('/')
else:
form = PasswordForm()
form1 = PasswordVerificationForm()
return render(request,"forget_password.html", {"form": form, "form1":form1})
Following is my forget_password.html
<div class="container">
<div class="main">
<div class="row justify-content-center">
<div class="col-md-4">
<div class="login-form">
<div class="row">
<div class="col-md-12">
<div class="login-title-holder">
<h4>Forgot Password</h4>
</div>
</div>
<form method="post">
<div class="form-group col-md-12">
<div class="input-group">
{{ form1.question | add_class:'form-control' }}
<span class="input-group-append">
<div class="input-group-text input-group-icon"><i class="fa fa-question" aria-hidden="true"></i></div>
</span>
</div>
</div>
<div class="form-group col-md-12">
<div class="input-group">
{{ form1.answer | add_class:'form-control' }}
<span class="input-group-append">
<div class="input-group-text input-group-icon "><i class="fa fa-comment" aria-hidden="true"></i></div>
</span>
</div>
</div>
<div class="col-md-12">
{% if messages %}
{% for message in messages %}
<div {% if message.tags %} class="alert {{ message.tags }} text-center"{% endif %}>
×
{{ message }}
</div>
{% endfor %}
{% endif %}
<input type="submit" name = "verify" formmethod="post" style="visibility: hidden;">
</div>
</form>
<form method="post">
<div class="form-group col-md-12">
<div class="input-group">
{{ form.password | add_class:'form-control' }}
<span class="input-group-append">
<div class="input-group-text input-group-icon"><i class="fa fa-key" aria-hidden="true"></i></div>
</span>
</div>
</div>
<div class="form-group col-md-12">
<div class="input-group">
{{ form.password_confirm | add_class:'form-control' }}
<span class="input-group-append">
<div class="input-group-text input-group-icon"><i class="fa fa-key" aria-hidden="true"></i></div>
</span>
</div>
</div>
<div class="col-md-12">
<div class="button-holder">
Cancel
<button class="login-btn" type="submit" formmethod="post" name="create">Create</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
If I enter the security answer first, based on the condition, if true, it enables the textfields for password and password_confirm.
But it's not creating the new password.
However, if I change the disabled = False in PasswordForm then it creating the new password successfully.
I want to know why it's not executing the code after the first form executes successfully.
Thanks!

You really should chain this into 2 urls, rather then trying 2 forms in one page. You can only submit one form and this is the problem you're facing. Once you have submitted the security question, you instantiate the form again with fields disabled:
form = PasswordForm(request.POST or None)
And now they do not get enabled, because the submit button called 'verify' from form1 is no longer present, so the code in that branch is not executed.
Let's say url is /password_reset/ - a rough outline (untested):
#login_required
#csrf_exempt
def security_question(request):
form = PasswordVerificationForm(request.POST)
if request.method == 'POST':
if form.is_valid():
token = generate_strong_token() # Implement: generate a strong token, url safe
request.session["password_reset_token"] = token
return redirect(f'/password_reset/{token}/')
else:
return render(...)
#login_required
#csrf_exempt
def change_password(request, **kwargs):
form = PasswordForm(request.POST)
token = request.session.get('password_reset_token')
if token == kwargs['token']:
if request.method == 'POST' and form.is_valid():
del request.session['password_reset_token']
# handle password change and redirect to wherever
else:
return render(...)
else:
raise SecurityError('Invalid token')
Your urls would be something like:
urlpatterns = [
re_path('password_reset/(?P<token>[0-9A-F]{32})/', change_password)
path('password_reset/', security_question)
]

Related

Template not displaying Validation error (Django)

I'm trying to display the Validation Error in my template (register.html) but it's not displaying. What is wrong with this code?
and one more question "how I can display email already exist in this form"
I don't know how to display the "email already exist".
The Codes Goes here.
forms.py
from django.contrib.auth.models import User
from django import forms
from .models import *
from django.utils.translation import gettext as _
class RegisterForm(forms.ModelForm):
username = forms.CharField(widget=forms.TextInput())
password = forms.CharField(widget=forms.PasswordInput())
email = forms.CharField(widget=forms.EmailInput())
class Meta:
model = Customer
fields =["full_name", "username", "email", "password"]
def clean_username(self):
uname = self.cleaned_data.get('username')
if User.objects.filter(username = uname).exists():
raise forms.ValidationError(_('Customer with this username already exists'), code='invalid')
return uname
def __init__(self, *args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs) # Call to ModelForm constructor
self.fields['username'].widget.attrs['style'] = 'width:500px; height:40px;'
self.fields['password'].widget.attrs['style'] = 'width:500px; height:40px;'
self.fields['email'].widget.attrs['style'] = 'width:500px; height:40px;'
self.fields['full_name'].widget.attrs['style'] = 'width:500px; height:40px;'
I can't display the Error Message on above code Customer with this username already exists
views.py
from django.shortcuts import render, redirect
from django.views.generic import CreateView, View, FormView
from django.contrib.auth import authenticate, login, logout
from django.urls import reverse_lazy
from .forms import *
# Create your views here.
class customerRegister(CreateView):
template_name = "register.html"
form_class = RegisterForm
success_url = reverse_lazy("main_app:base")
def form_valid(self, form):
username = form.cleaned_data.get("username")
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
user = User.objects.create_user(username, email, password)
form.instance.user = user
login(self.request, user)
return super().form_valid(form)
def get_success_url(self):
if "next" in self.request.GET:
next_url = self.request.GET.get("next")
return next_url
else:
return self.success_url
register.html
<body style="background-color: #95a5a6">
{% if error %}
<div class="alert alert-dismissible alert-danger">
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
<strong>Oh snap!</strong>{{form.non_field_errors}}
</div>
{% endif %}
<div class="container-register mx-auto">
<form action="{% url 'account:register' %}" method="post">
{% csrf_token %}
<fieldset>
<h2 class="text-center" style="margin-top: 50px">Register</h2>
<div class="form-group">
<label class="col-form-label mt-4" for="inputDefault">Full Name*</label><br>
{{form.full_name}}<br>
</div>
<div class="form-group">
<label class="col-form-label mt-4" for="inputDefault">Username*</label><br>
{{form.username}}<br>
</div>
<div class="form-group">
<label for="exampleInputEmail1" class="form-label mt-4 ">Email address*</label><br>
{{form.email}}<br>
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div class="form-group">
<label for="exampleInputPassword1" class="form-label mt-4">Password*</label><br>
{{form.password}}<br>
</div>
<br/>
<div class="text-center">
<button type="submit" class="btn btn-lg btn-primary">Register</button>
</div>
</fieldset>
</form>
<hr>
<h5 class="text-center" style="margin-top: 50px">Already Registered?<a class="nav-link" href="{% url 'account:login'%}">Log in</a></h5>
</div>
</body>
In your template you have {% if error %} which does not exist as you are not passing the template context error. Inside the template if you are then accessing {{form.non_field_errors}} which will exist if there are errors.
So it should be {% if form.non_field_errors %} like so:
{% if form.non_field_errors %}
<div class="alert alert-dismissible alert-danger">
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
<strong>Oh snap!</strong>{{form.non_field_errors}}
</div>
{% endif %}
See related StackOverflow post here for customising the email error message.

Django: can't login after editing user details

I'm trying to find a solution for 2 days now... can't figure out why login does not work for me once I have changed any user details.
Normal flow works fine for me: user registers, logs in and out without a problem. But I thought it would be good to have profile change option where a user can change username, password or email. I did implement this, but after a user changes anything (even email), the login form does not admit him.
Here is my views.py:
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordChangeForm
from .forms import ContactForm, CreateUserForm, EditUserForm
class ProfileView(UpdateView):
template_name = 'boat_app/edit_profile.html'
form_class = UserChangeForm
success_url = reverse_lazy('anchored')
def get_object(self):
return self.request.user
class LoginView(TemplateView):
template_name = 'boat_app/login.html'
success_url = reverse_lazy('category_home')
def post(self, request):
print(request)
user = authenticate(request, username=request.POST.get('username'), password=request.POST.get('password'))
if user is not None:
print('user not none')
login(request, user)
return HttpResponseRedirect(reverse('anchored'))
else:
print('user none')
messages.info(request, 'Username OR password is incorrect')
return HttpResponseRedirect(reverse('login'))
And forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
class EditUserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'email')
After changing a user I see this change in admin interface, so it does work. But I can't see a reason why the system does not see this relation. Any way to debug what exactly is going on there?
UPDATE
I've tried changing the user via admin backend - all works fine. I've also tried using {{ form.as_p }} instead of my custom template for ProfileView - and this also worked! So apparently there is something fishy going on with my html template which ruins the update view and does nont allow to collect data for future login.
Here is my 'boat_app/edit_profile.html'
{% block body_block %}
<div class="row align-items-center vh-100">
<div class="col-lg-4 d-none d-md-block">
</div>
<div class="col-lg-4 d-flex align-items-center">
<div class="container p-3 text-center bg-light">
<div class="my-3">
<h1>Change your details</h1>
<p>Did something change?</p>
</div>
<form method="post">
{% csrf_token %}
<div class="form-group row px-3">
<label for="{{ form.username.id_for_label }}">{{form.username.label}}</label>
{% render_field form.username class="form-control" %}
</div>
<div class="form-group row px-3">
{{ form.email.errors }}
<label for="{{ form.email.id_for_label }}">{{form.email.label}}</label>
{% render_field form.email class="form-control" %}
</div>
<div class="form-group row px-3">
{{ form.password.errors }}
<label for="{{ form.date_joined.id_for_label }}">{{form.date_joined.label}}</label>
{% render_field form.date_joined class="form-control" %}
</div>
<div class="form-group row text-left px-3">
<p>If you need to change password, click here.</p>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
</div>
</div>
<div class="col-lg-4 d-none d-md-block">
</div>
</div>
{% endblock %}

Django Forms Invalid but no Errors

Maybe it might be an oversight but I do not know the point where I am getting it wrong.
My form is rendered correctly but it keeps failing without errors.
forms.py
from crispy_forms.helper import FormHelper
from django import forms
from django.utils.translation import ugettext as _
class BeneficiaryForm(forms.Form):
"""Add Beneficiary template form"""
# Form fields
account_currency = forms.ModelChoiceField(queryset=Currency.objects.all(), empty_label=_('Select account currency'))
bank_account_type = forms.CharField(max_length=50, required=False)
email = forms.CharField(max_length=150, required=False, help_text=_("We'll notify them when a transfer is made"))
name = forms.CharField(max_length=50, required=False)
swift_code = forms.CharField(max_length=11, required=False,
widget=forms.TextInput(attrs={'placeholder': 'MSBCCNBJ001'}))
iban = forms.CharField(max_length=34)
def __init__(self, *args, **kwargs):
super(BeneficiaryForm, self).__init__()
self.helper = FormHelper()
self.helper.form_show_labels = False
views.py
def beneficiaries(request):
"""View function for viewing Beneficiaries and adding a Beneficiary instance"""
if request.method == 'POST':
form = BeneficiaryForm(request.POST)
if form.is_valid():
print("Form is valid")
print(request.POST['bank_account_type'])
print(request.POST['email'])
print(request.POST['name'])
print(request.POST['iban'])
print(request.POST['swift_code'])
print("Form is invalid")
print(form.errors)
form = BeneficiaryForm()
context = {
'form': form
}
return render(request, 'dashboard/beneficiaries.html', context)
and in my rendered form. I have this block to show errors and nothing shows up
HTML
<form action="{% url 'beneficiary_index' %}" method="post">
{% csrf_token %}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
{% if field != '__all__' %}
<strong>{{ field.label }}:</strong>
{% endif %}
{{ error|escape}}
</div>
{% endfor %}
{% endfor %}
{% endif %}
<div class="form-group">
<div class="form-label-group">
<label class="form-label" for="default-01">{% trans "Account currency" %}</label>'
</div>
{{ form.account_currency | as_crispy_field }}
</div>
<div class="form-group">
<div class="form-label-group">
<label class="form-label" for="default-01">{% trans "Bank Account type" %}</label>
</div>
{{ form.bank_account_type | as_crispy_field }}
</div>
<div class="form-group">
<div class="form-label-group">
<label class="form-label" for="default-01">Their email(optional)</label>
</div>
{{ form.email | as_crispy_field }}
</div>
<div class="form-group">
<div class="form-label-group">
<label class="form-label" for="default-01">Full name of account holder</label>
</div>
{{ form.name | as_crispy_field }}
</div>
<h6>{% trans "Recipient Bank Information" %}</h6>
<hr>
<div class="form-group">
<div class="form-label-group">
<label class="form-label" for="default-01">Swift code</label>
</div>
{{ form.swift_code | as_crispy_field }}
</div>
<div class="form-group">
<div class="form-label-group">
<label class="form-label" for="default-01">IBAN</label>
</div>
{{ form.iban | as_crispy_field }}
</div>
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">{% trans 'Add Beneficiary' %}</button>
</div>
</form>
This is the Html to the form. I have just tried all the suggestions and still without the errors.
Form is Invalid is the only thing printed on screen without the form.errors
You need to create the GET request empty form in the else block or return the request in the POST block.
You are re-creating an empty form before returning the response.
def beneficiaries(request):
"""View function for viewing Beneficiaries and adding a Beneficiary instance"""
if request.method == 'POST':
form = BeneficiaryForm(request.POST)
if form.is_valid():
print("Form is valid")
print(request.POST['bank_account_type'])
print(request.POST['email'])
print(request.POST['name'])
print(request.POST['iban'])
print(request.POST['swift_code'])
# do other stuff like saving to DB
# then redirect
else:
print("Form is invalid")
print(form.errors)
elif request.method == 'GET':
form = BeneficiaryForm()
else:
# maybe return 404
pass
context = {
'form': form
}
return render(request, 'dashboard/beneficiaries.html', context)
Or maybe you can try Class Based Views, to avoid the if-else block for GET and POST requests.
Try adding this to the place you want the error to appear (In the HTML file)
Better if you use it inside the tags.
{% if form.errors %}
<p>Form is invalid</p>
{% endif %}
I Hope this answers the question.

Unexpexted MultiValueDictKeyError in signup code

I am new to Django. I am creating a signup page. But I am having an unexpected MultiValueDictKeyError with Exception value fname.
views.py:
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.contrib import auth
# Create your views here.
def signup(request):
if request.method == 'POST':
# User has and wants account now
if request.POST['password1'] == request.POST['password2']:
# Check if username already exists
try:
user = User.objects.get(username=request.POST['uname'])
return render(request, 'accounts/signup.html',{'error':'username already exist'})
# If username unoccupied
except User.DoesNotExist:
user = User.objects.create_user(fname = request.POST['fname'],lname = request.POST['lname'],email = request.POST['email'],uname = request.POST['uname'],password = request.POST['password1'])
# updating new user
auth.login(request,user)
return redirect('home')
else:
return render(request,'accounts/signup.html')
def login(request):
if request.method == 'POST':
#
user = auth.authenticate(username = request.POST['username'],password = request.POST['password'])
if user is not None:
auth.login(request,user)
return redirect('home')
else:
return render(request, 'accounts/login.html',{'error': 'username or password incorrect'})
else:
#
return render(request,'accounts/login.html')
def logout(request):
if request.method == 'POST':
auth.logout(request)
return redirect('home')
sign up page:
{% extends 'base.html'%}
{% block content %}
<div class="container-fluid" style="background-image: linear-gradient(to right, #1a1aff , #000099);padding: 10vh">
<div class="row">
<div class="col center" style="color: white;padding: 05vw">
<h1> Sign Up Now! </h1>
<br>
<h2> Become the part world's first personalized <br> Network <h2>
</div>
<div class="col-5 center container" style="color:black;padding: 02vw;background-color: white;">
<span>
<center>
<h1>Sign Up</h1>
</center>
<br>
</span>
<form action="{% url 'signup' %}" method="POST">
{% csrf_token %}
{% if error %}
<p style="color:red "> {{error}} </p>
{% endif %}
<h3>First Name</h3>
<input type="text" id="fname" name="firstname" placeholder="Your name..">
<br>
<h3>Last Name</h3>
<input type="text" id="lname" name="lastname" placeholder="Last Name">
<br>
<h3>Email</h3>
<input type="email" id="email" name="email" placeholder="Email Address">
<br>
<h3>Username</h3>
<input type="text" id="uname" name="uname" placeholder="Username">
<br>
<h3>Password</h3>
<input type="password" id="password" name="password1" placeholder="Password">
<br>
<h3>Confirm Password</h3>
<input type="password" id="password" name="password2" placeholder="Password">
<br>
<br>
<input type="submit" value="Sign Up Now">
</form>
</div>
</div>
</div>
enter code here
{% endblock %}
The field is firstname, not fname. This is why you should use Django forms rather than accessing the POST directly

Flask landing page contact form

I learn Flask and started to make a simple landing page for the project. Here is the route that handles the contact form
#app.route("/courses")
def courses():
form = ContactForm()
if request.method == 'POST':
if form.validate() == False:
flash('All fields are required.')
return render_template('courses.html', title="contact", form=form)
else:
msg = Message(recipients=['coterakg#gmail.com'])
msg.body = """From: %s <%s>%s"""%(form.name.data, form.email.data, form.message.data)
mail.send(msg)
return render_template('courses.html', title="contact", success=True)
if request.method == 'GET':
return render_template('courses.html', title="contact", form=form)
Then there is a template part which has the form
<form class="form-horizontal" action="{{ url_for('index') }}" id="contactform" method="post">
<div class="modal-header">
<h4>Задайте нам любой вопрос!</h4>
</div>
<div class="modal-body">
{{ form.hidden_tag() }}
<div class="form-group">
<label for="contact-name" class="control-label">Имя:</label>
<div>
{{ form.name }}
</div>
</div>
<div class="form-group">
<label for="contact-email" class="control-label">Email:</label>
<div>
{{ form.email }}
</div>
</div>
<div class="form-group">
<label for="question" class="control-label">Ваш вопрос:</label>
<div>
{{ form.message }}
</div>
</div>
</div>
<div class="modal-footer">
<a class="close-reveal-modal">×</a>
<button class="button" type="submit" value="contact" data-reveal-id="closeModal">Отправить</button>
<div data-reveal class="reveal-modal" id="closeModal">
<h1>Спасибо за Ваш вопрос!</h1>
<a class="close-reveal-modal">×</a>
</div>
</div>
</form>
And lastly - the part with form
from flask.ext.wtf import Form
from wtforms import StringField, BooleanField, SubmitField
from wtforms.validators import DataRequired
class ContactForm(Form):
name = StringField("Name", validators=[DataRequired()])
email = StringField("Email", validators=[DataRequired()])
message = StringField("Message", validators=[DataRequired()])
submit = SubmitField("Send")
Any ideas why this is not working?
here is a good examples for you https://github.com/jawr/flask-contact/blob/master/main.py
And detailed steps here http://code.tutsplus.com/tutorials/intro-to-flask-adding-a-contact-page--net-28982
I would also suggest you to use some 3rd party service as a mail server (Mandrill, etc).