Django form validation with Bootstrap 5 - django

I want to create django login form with bootstrap 5. How can i ensure that the form is valid? Can i styling raise validationError with bootstrap in template?
Here is my code:
forms.py
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField()
def clean(self):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
# Check if user and password is matching and exists
user = authenticate(username=username, password=password)
if not user:
raise forms.ValidationError("This is an invalid user.")
login_page.html
<form method="POST" class="row g-3 needs-validation" novalidate>
{% csrf_token %}
<input type="text" name="username" class="form-control" placeholder="Username" required>
<div class="invalid-feedback">{{ #raise ValidationError here }}</div>
<input type="password" name="password" class="form-control" placeholder="Password" required>
<div class="invalid-feedback">{{ #raise ValidationError here }}</div>
<input class="btn btn-primary" type="submit" value="Login">
Can i do that? Or is there a better solution to create login form validation?
Thankyou.

you can pass validation here like this in your forms.py
forms.py
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
def clean(self, *args, **kwargs):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
if username and password:
user = authenticate(username=username, password=password)
if not user:
raise forms.ValidationError("This user doesn't exist")
if not user.check_password(password):
raise forms.ValidationError("Incorrect Password")
if not user.is_active:
raise forms.ValidationError("User no longer Active")
return super(LoginForm,self).clean(*args,**kwargs)

Related

The Django password reset form is not working, where is the problem?

My motive is to reset the password by sending an email to the user. When the user will click on the link that sends by mail will open an Html page, which will have a password and confirm password form. The email sending system is working well, when I click on the link that sends by mail opens a password reset form. But the problem is, the password reset form is not working. Password not being changed. Where did the actual problem occur? Password not being change. Where did the actual problem occur? Please give me a relevant solutionšŸ˜¢...
helper.py:
from django.core.mail import send_mail
from django.conf import settings
def send_forget_password_mail(email , token ):
subject = 'Your forget password link'
message = f'Hi , click on the link to reset your password http://127.0.0.1:8000/changepassword/{token}/'
email_from = settings.EMAIL_HOST_USER
recipient_list = [email]
send_mail(subject, message, email_from, recipient_list)
return True
views.py:
def ChangePassword(request, token):
context = {}
try:
profile_obj = User.objects.filter(forget_password_token=token).first()
print(profile_obj)
if request.method == 'POST':
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('reconfirm_password')
user_id = request.POST.get('user_id')
if user_id is None:
messages.warning(request, 'No user id found.')
return redirect(f'/changepassword/{token}/')
if new_password != confirm_password:
messages.warning(request, 'both should be equal.')
return redirect(f'/changepassword/{token}/')
return redirect('login_user')
context = {'user_id' : profile_obj.user.id}
except Exception as e:
print(e)
return render(request, 'new_password.html', context)
def forgot_password(request):
try:
if request.method == 'POST':
email = request.POST.get('email')
if not User.objects.filter(email=email).first():
messages.warning(request, 'Not user found with this username.')
return redirect('forgot_password')
user_obj = User.objects.get(email = email)
token = str(uuid.uuid4())
send_forget_password_mail(user_obj.email , token)
messages.success(request, 'an email is send.')
return redirect('forgot_password')
except Exception as e:
print(e)
context ={
}
return render(request,'forgot.html', context)
urls.py:
path('changepassword/<token>/', views.ChangePassword, name="changepassword"),
path('forgot_password/', views.forgot_password, name="forgot_password"),
forgot.html:
<form method="POST" action="#!" class="needs-validation mt-5" style="font-size:13px;" novalidate="" autocomplete="off">
{% csrf_token %}
<input id="email" type="email" class="form-control " style="font-size:13px;" name="email" value="" required autofocus>
<button type="submit" class="btn btn-outline-dark ms-auto" style="font-size: 12px;"> Send Link </button>
</form>
new_password.html
<form action="" method="POST" class="needs-validation poppins_font" style="font-size: 13px;" novalidate=""autocomplete="off">
{% csrf_token %}
<input id="password" style="font-size: 13px;" type="password" class="form-control" name="new_password" required>
<input id="confirm_password" style="font-size: 13px;" type="password" class="form-control" name="reconfirm_password" required>
<input type="hidden" name="user_id" value="{{user_id}}">
<button type="submit" class="btn btn-outline-dark ms-auto" style="font-size: 12px;">Set</button>
</form>
models.py:
class User(AbstractUser):
email = models.EmailField( max_length=150,unique=True,error_messages={"unique":"The email must be unique."})
forget_password_token = models.CharField(max_length=100, blank=True, null=True)
I think the problem is that you're not saving the password to the database, and therefore the password isn't changed. Try something along the lines of:
def ChangePassword(request, token):
context = {}
try:
profile_obj = User.objects.filter(forget_password_token=token).first()
print(profile_obj)
if request.method == 'POST':
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('reconfirm_password')
user_id = request.POST.get('user_id')
if user_id is None:
messages.warning(request, 'No user id found.')
return redirect(f'/changepassword/{token}/')
if new_password != confirm_password:
messages.warning(request, 'both should be equal.')
return redirect(f'/changepassword/{token}/')
else:
profile_obg.password = new_password
profile_obg.save()
return redirect('login_user')
context = {'user_id' : profile_obj.user.id}
except Exception as e:
print(e)
return render(request, 'new_password.html', context)
Notice the added else statements, which means "if no error, save the password to the database"

Django authenticate user does not work after logging in

I'm trying to create a custom session-based login in Django using a custom user model and a custom login template.
For some reasons it worked at first but now the authenticate method from django.contrib.auth is not authenticating user. When it did work, the login and signup button were hidden.
users/urls.py
app_name = 'users'
urlpatterns = [
path('login/', login_user, name='login_user'),
path('logout/', logout_user, name='logout_user'),
]
users/views.py
app_name = 'users'
def login_user(request):
django_logout(request)
message = ''
if request.method == 'POST':
email = request.POST['email']
password = request.POST['password']
user = authenticate(request, email=email, password=password)
if user is not None:
django_login(request, user)
return redirect('homepage')
else:
message = "Log in failed!"
messages.error(request, message)
return redirect('users:login_user')
else:
return render(request, 'users/login.html')
#login_required(login_url='users/login/')
def logout_user(request):
django_logout(request)
templates/users/login.html
<form class="bg-white rounded-5 shadow-5-strong p-5" method="post" action="/">
{% csrf_token %}
<!-- Email input -->
<div class="form-outline mb-4">
<label class="form-label" for="form1Example1">Email address</label>
<input type="email" name="email" id="form1Example1" class="form-control" />
</div>
<!-- Password input -->
<div class="form-outline mb-4">
<label class="form-label" for="form1Example2">Password</label>
<input type="password" type="password" id="form1Example2" class="form-control" />
</div>
<!-- Submit button -->
<button type="submit" class="btn btn-primary btn-block">Sign in</button>
</form>
users/models.py
class CustomUserManager(BaseUserManager):
def create_superuser(self, email, password):
if email is None:
raise TypeError('Users should have an Email')
if password is None:
raise TypeError('Password should not be none')
user = self.create_user(email, password)
user.is_superuser = True
user.is_staff = True
if user.is_superuser is not True:
raise ValueError(
'Superuser must be assigned to is_staff=True.')
if user.is_staff is not True:
raise ValueError(
'Superuser must be assigned to is_superuser=True.')
user.save()
return user
def create_user(self, email, password):
if email is None:
raise TypeError('Users should have an Email')
if password is None:
raise TypeError('Users must have a password')
email = self.normalize_email(email)
user = self.model(email=email)
user.set_password(password)
user.save()
return user
AUTH_PROVIDERS = {'facebook': 'facebook', 'google': 'google',
'twitter': 'twitter', 'email': 'email'}
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True, db_index=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
about = models.TextField(_(
'about'), max_length=500, blank=True)
auth_provider = models.CharField(
max_length=255, blank=False,
null=False, default=AUTH_PROVIDERS.get('email'))
USERNAME_FIELD = 'email'
objects = CustomUserManager()
def __str__(self):
return self.email
My sign in button in homepage.html
<a href="{% url 'users:login_user' %}">
<button type="button" class="btn btn-link px-3 me-2">
Login
</button>
</a>
Could you show me the way to solve this? Thank you!
Change your form like this
<form class="bg-white rounded-5 shadow-5-strong p-5" method="post" action="{% url 'users:login_user' %}">
{% csrf_token %}
<!-- Email input -->
<div class="form-outline mb-4">
<label class="form-label" for="form1Example1">Email address</label>
<input type="email" name="email" id="form1Example1" class="form-control" />
</div>
<!-- Password input -->
<div class="form-outline mb-4">
<label class="form-label" for="form1Example2">Password</label>
<input type="password" name="password" type="password" id="form1Example2" class="form-control" />
</div>
<!-- Submit button -->
<button type="submit" class="btn btn-primary btn-block">Sign in</button>
</form>
MultiValueDictKeyError at /users/login/ 'password'
this is because you're trying to access password value from request like this request.POST['password'] but you've not set name to your input(password) that's why it is giving you an error

login based on user roles

problem with my assignment....
I also need to make users login based on whether their role (usertype) is 'reader' or 'client' to be redirected to the proper welcome page. Plus i want to use my custom model (User's username & password) for login credentials. I have read the django docs custom auth but i still don't know i will implement it into my project.
models.py
class User(models.Model):
id = models.AutoField(primary_key=True, unique=True)
title = models.CharField(max_length='10')
surname = models.CharField(max_length='50')
firstname = models.CharField(max_length='50')
username = models.CharField(max_length='50', unique=True)
password = models.CharField(max_length='50')
email = models.EmailField(max_length='50')
phone = models.BigIntegerField(max_length='12')
city = models.CharField(max_length='50')
country = models.CharField(max_length='50')
usertype = models.CharField(max_length=13)
views.py
def login(request):
c = {}
c.update(csrf(request))
return render_to_response('login.html', c)
def auth_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return HttpResponseRedirect('adminwelcome')
else:
return HttpResponseRedirect('invalid')
template
{% extends "main.html" %}
{% block title %}Log In - {{ block.super }}{% endblock %}
{% block content %}
{% if form.errors %}
<p>Sorry, that is not a valid username or password</p>
{% endif %}
<form action = "auth_view" method="post"> {% csrf_token %}
<label for="username">Username:</label>
<input type="text" name="username" value="" id="username" />
<br />
<label for="password">Password:</label>
<input type="password" name="password" value="" id="password" />
<br />
<input type="submit" value="Login" />
</form>
<p>Not Registered? Create Account </p>
{% endblock %}
What i did was that when my User model form is being saved, it should get the username, password and email and create a user in the Django auth User table using this line of code
User.objects._create_user(request.POST['username'], request.POST['email'], request.POST['password'],False,False)
This is the full code in the views.py
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
User.objects._create_user(request.POST['username'], request.POST['email'], request.POST['password'],False,False)
# Redirect to the document list after POST
return HttpResponseRedirect('register_success')
else:
form = RegisterForm()
args = {}
args.update(csrf(request))
args['forms'] = RegisterForm()
return render_to_response('register.html', args)
Then for the login based on roles, I had to make the user a staff from the admin end by setting the 'is_staff' = true. After that, all i had to do was pass the 'is_staff==True' in the auth_view request during login authentication. A bit dirty but it does the trick. Any further optimization is appreciated. Cheers.
Views.py
def auth_view(request):
username1 = request.POST.get('username', '')
password1 = request.POST.get('password', '')
user = auth.authenticate(username=username1, password=password1)
#check if user has been set to staff (reader), redirect to reader welcome
if user is not None and user.is_staff==True:
auth.login(request, user)
return HttpResponseRedirect('readerwelcome')
#check if user is not staff(client), redirect to client welcome
elif user is not None:
auth.login(request, user)
return HttpResponseRedirect('clientwelcome')
#if login details not found, return error page
else:
return HttpResponseRedirect('invalid')

ValueError : The given username should be set

I am trying to write my method to add a User type object on registration. Here is the code:
views.py
def registration(request):
c= {}
c.update(csrf(request))
state = "Please Register below..."
username = None
email = None
password = None
user_success = None
user_created = None
if request.POST:
username = request.POST.get('username')
email = request.POST.get('email')
password = request.POST.get('password')
print "username ",username
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
user_created = True
else:
user_created = False
else:
user = User.objects.create_user(username=username,password=password,email=email)
user.save()
user.is_active = True
user_success = True
return render_to_response('register.html',{'success':user_success,'created':user_created,'username': username},context_instance = RequestContext(request))
forms.py
class RegistrationForm(forms.Form):
username = forms.CharField()
email = forms.EmailField()
password = forms.CharField()
templates/register.html is:
{% extends "base.html" %}
{% block pageContent %}
<div class="container">
<form action="/register" method="post">
{% csrf_token %}
username:
<input type="text" name="username" value="{{ username}}" /><br />
password:
<input type="password" name="password" value="" /><br />
Email:
<input type="text" name="email" value="{{email}}" /><br />
<input type = 'submit' value='Register' />
</form>
</div>
{% endblock %}
Can anyone please help me spot the error? Also let me know if I am doing the registration right
The value of username at this point must evaluate to True.
user = User.objects.create_user(username=username,password=password,email=email)
# ^^^^^^^^ this can't be a bool() false
Why? That error message is very specific.. it's called from this specific place in django auth:
def create_user(self, username, email=None, password=None, **extra_fields):
"""
Creates and saves a User with the given username, email and password.
"""
now = timezone.now()
if not username:
raise ValueError('The given username must be set')
Can you be 100% positive username is the right value? It sounds like it's an empty string.
I found the error. The error was in indentation of the view.py.
if user is not None:
part of the code should be only if the request type is POST. So that needed indentation.

Django. Error message for login form

I make login/password form:
model:
class LoginForm(forms.Form):
username = forms.CharField(max_length=100)
password = forms.CharField(widget=forms.PasswordInput(render_value=False),max_length=100)
view:
def login_view(request):
if request.method == 'POST':
username = request.POST['email']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None and user.is_active:
login(request, user)
return HttpResponseRedirect("/n1.html")# Redirect to a success page.
return HttpResponseRedirect("/login")
form=LoginForm()
return render(request, 'enter.html', {'login_form': LoginForm})
urls:
(r'^login/$', login_view),
template:
{% if form.errors %}
<p>Something is wrong</p>
{% endif %}
<form class="form-signin" action="" method="post">
<h2 class="form-signin-heading">Login</h2>
{% csrf_token %}
<input class="input-block-level" type="text" name="email" value="" id="email" placeholder="Email">
<input class="input-block-level" type="password" name="password" value="" id="username" placeholder="Password">
<button class="btn btn-large btn-primary" type="submit">Login</button>
<input type="hidden" name="next" value="{{next|escape}}" />
</form>
I use redirect to login page then login or password is wrong, but I want to make error message in this case. Why construction {% if form.errors %} doesn't work? Thx!
Because the form has no idea an error occurred.
When you construct the form here:
form=LoginForm()
You're constructing it without passing it any information. It doesn't know anything about the POST the user just did, or that the the login failed, or that the password was missing, or whatever the error was.
Here's what my login forms look like:
class LoginForm(forms.Form):
username = forms.CharField(max_length=255, required=True)
password = forms.CharField(widget=forms.PasswordInput, required=True)
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if not user or not user.is_active:
raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
return self.cleaned_data
def login(self, request):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
user = authenticate(username=username, password=password)
return user
We override the form's clean method, so that if the form passes validation we can check the user's credentials. We also put a login method on the form object itself, to make our view cleaner.
Next, in our view, we want to do this:
def login_view(request):
form = LoginForm(request.POST or None)
if request.POST and form.is_valid():
user = form.login(request)
if user:
login(request, user)
return HttpResponseRedirect("/n1.html")# Redirect to a success page.
return render(request, 'enter.html', {'login_form': form })
We instantiate the form and hand it the request.POST to check against.
If we have a POST, we check if the form is valid. The form's "clean" method will get called, and check the user credentials for us.
If the credentials fail, we raise an error, which we need to show in our template.
Errors raised by the form (but not attached to a field) are stored in non_field_errors, which can be displayed like so:
{% if form.non_field_errors %}
<ul class='form-errors'>
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
When you redirect, I'm not sure you send the context of your page. So when you redirect to the /login/ page, django tinks it's a new form which is loaded.