Django password validation not working - python

I am using my own custom User model, but I'm inheriting off of django.contrib.auth User model. I have a username, email, and password field. I don't explicitly add the password field because it gets added by default by the inheritance. When I try to create a superuser through the command line, the normal default Django password validation is working correctly. However, when I have a sign up form, it is not. Email and username validation are working properly when I click submit, but there is no password validation. I can enter whatever I want and it would accept the password.
Here's my forms.py
class RegisterForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'email', 'password']
username = forms.CharField(label='Username', widget=forms.TextInput(attrs={'placeholder': 'Username:'}))
email = forms.EmailField(label='Email', widget=forms.EmailInput(attrs={'placeholder': 'Email:'}))
password = forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'placeholder': 'Password:'}))
Here's my view:
class RegisterView(SuccessMessageMixin, View):
form_class = RegisterForm
template_name = 'oauth/auth_form.html'
success_message = "You have successfully created an account!"
# Display blank form
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False) # Do not save to table yet
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
# Let's try to login the user
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('profiles: index')
return render(request, self.template_name, {'form': form})
How can I make it so that the password field gets validated correctly with the default password validation from Django?

Django has some utils to integrate password validation. The easiest would be to call the validate_password function in the field specific clean_password method of the form, but since you need a user instance for some validators, I shall demonstrate its use in the view:
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
class RegisterView(SuccessMessageMixin, View):
# ...
def post(self, request):
if form.is_valid():
user = form.save(commit=False) # Do not save to table yet
username = form.cleaned_data['username']
password = form.cleaned_data['password']
try:
validate_password(password, user)
except ValidationError as e:
form.add_error('password', e) # to be displayed with the field's errors
return render(request, self.template_name, {'form': form})
# ...
return render(request, self.template_name, {'form': form})

Related

Register in Django with email as unique

I am new to Django and I am trying to make my first registration app. I used the UserCreationForm. When I run the code and try to register, if I put the same email form many user it doesn't give me any error.
My forms.py
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class RegisterForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
my views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout
from django.contrib import messages
# Create your views here.
from .forms import RegisterForm
def registerUser(request):
form = RegisterForm()
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
return redirect('login')
else:
form = RegisterForm()
return render(request, 'register.html', {'form':form})
def loginUser(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username and password:
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
messages.error(request, 'Username or Password is Incorrect')
else:
messages.error(request, 'Fill out all the fields')
return render(request, 'login.html', {})
def home(request):
return render(request, 'home.html', {})
def logoutUser(request):
logout(request)
return redirect('home')
def Profile(request):
return render(request, 'profile.html', {})
As said by Harshil Suthar in the comments, overriding the default user model is the best practise (https://docs.djangoproject.com/en/3.1/topics/auth/customizing/#a-full-example), but it may be a lot of effort in your case if you just want to check unique email when using your form.
You can solve this problem using the clean_< attribute > method of your form. Note that it will just be effective when using this form. So, for example a superuser will still be able to have the same email as another user...
# Other imports...
from django.core.exceptions import ValidationError
class RegisterForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
def clean_email(self):
email = self.cleaned_data["email"]
if User.objects.filter(email=email).exists():
raise ValidationError("An user with this email already exists!")
return email

Django authenticate method not working

I am trying to use the default Django from django.contrib.auth authenticate() method to authenticate if the user exists. I am doing this right after the user registers. The user registers and their username, email, and password is inputted into the database, but when I call authenticate(username=username, password=password) it is returning None for some reason. The password is being stored as a hash and it is worth to note that I am using my own custom User model, but inheriting from django.contrib.auth User model.
Here's my view:
class RegisterView(SuccessMessageMixin, View):
form_class = RegisterForm
template_name = 'oauth/auth_form.html'
success_message = "You have successfully created an account!"
# Display blank form
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False) # Do not save to table yet
username = form.cleaned_data['username']
password = form.cleaned_data['password']
try:
validate_password(password, user)
except ValidationError as e:
form.add_error('password', e) # to be displayed with the field's errors
return render(request, self.template_name, {'form': form})
user.set_password(password)
user.save()
# Let's try to login the user
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('http://google.com')
return render(request, self.template_name, {'form': form})
Why is it that the authenticate method is not working out for me?
Although #schwobaseggl 's answer should solve your issue, i.e. "No need to authenticate, just login directly", I've done something very similar in one of my older projects and maybe it helps you.
Here the registration process automatically logged in the user, and we were using email tokens as password:
def get_or_create_user(mobile):
UserModel = get_user_model()
try:
user = UserModel.objects.get(mobile=mobile)
except UserModel.DoesNotExist:
user = UserModel(mobile=mobile, username=mobile)
user.set_unusable_password()
user.save()
return user
...
class UserRegistrationAndLogin(View):
...
def post(self, request):
form = self.form_class(request.POST)
next_url = request.GET.get('next')
if form.is_valid():
entered_token = form.cleaned_data['otp']
if entered_token == self.token:
user = get_or_create_user(mobile=self.mobile)
login(request, user)
return redirect(next_url or settings.LOGIN_REDIRECT_URL)
else:
form.add_error('otp', 'OTP does not match!')
return render(request, self.template_name, context={'form': form, 'mobile': self.mobile})

user with that username already exists in Django

I wrote two views as the class in Django in order to do the Registration and Login for my website. But the problem is that the user objects get created successfully. But when I try to authenticate later getting the warning message showing that user with that username already exists in Django
The two views are given below
class RegistrationView(View):
form_class=RegistrationForm
template_name='eapp/user_registration_form.html'
def get(self,request):
form=self.form_class(None)
return render(request,self.template_name,{'form':form})
def post(self,request):
form=self.form_class(request.POST)
if form.is_valid():
user=form.save(commit=False)
#cleaned (normalized) data
username =form.cleaned_data['username']
password =form.cleaned_data['password']
email=form.cleaned_data['email']
user.set_password(password)
user.save()
return render(request,self.template_name,{'form':form,})
class LoginView(View):
form_class=LoginForm
template_name='eapp/user_login_form.html'
def get(self,request):
form=self.form_class(None)
return render(request,self.template_name,{'form':form})
def post(self,request):
form=self.form_class(request.POST)
if form.is_valid():
#cleaned (normalized) data
username =form.cleaned_data['username']
password =form.cleaned_data['password']
#authenticatin
user=authenticate(username=username,password=password)
if user is not None:
if user.is_active:
login(request,user)
return render(request,'eapp/index.html',{})
return render(request,self.template_name,{'form':form,})
here is my forms.py'
from django.contrib.auth.models import User
from django import forms
class RegistrationForm(forms.ModelForm):
password=forms.CharField(widget=forms.PasswordInput)
class Meta:
model=User
fields=['username','email','password']
class LoginForm(forms.ModelForm):
password=forms.CharField(widget=forms.PasswordInput)
class Meta:
model=User
fields=['username','password'
]
How can I solve this? ThankYou
Change your LoginForm for a Form without model:
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(label = 'Nombre de usuario')
password = forms.CharField(label = 'ContraseƱa', widget = forms.PasswordInput)
This way your form will validate that the fields are entered and will not take validations from the User model

Django AttributeError: 'User' object has no attribute 'set_password' but user is not override

I have the following error:
AttributeError: 'User' object has no attribute 'set_password'
The problem is I didn't override the class User:
My model.py:
class User(models.Model):
username = models.CharField(max_length=30)
password = models.CharField(max_length=30)
email = models.EmailField()
def __str__(self):
return self.username
My view.py:
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
print type(user)
# Cleaning and normalizing data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
# returns User objects if the credential are correct
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('website:home')
return render(request, self.template_name, {'form': form})
And this is my form.py:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control',
'type': 'password',
'placeholder': 'Enter your password'}))
class Meta:
model = models.User
I don't really know also if I should override the User class. In which case I should and in which case I shouldn't?
You need to inherit from AbstractUser to get access to set_password attribute. Instead of using models.Model use:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
...
Your User model is not the same as django's User model.
Reference custom user model
from django.contrib.auth.hashers import make_password
replace
user.set_password(password) by user.password = make_password('password')
it clear and work for me.
The User model in Django has .set_password but if you made your own you should try OneToOneField(User) from there you just have to make sure you save both in the views.
user_form = UserForm(data=request.POST)
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
profile = user.userprofile
profile.bio = request.POST['bio']
profile.save()

How can I prevent a logged in user from accessing a 'Log In' or 'Sign Up' page in Django version 1.9?

I'm pretty new to Python.
My problem is that I want to restrict users who are already logged in from being able to visit the log in and sign up pages.
Essentially, what I'm looking for is something like the #login_required decorator, that will allow access to these pages for users who are not logged in.
So far, I have
Looked at other SO questions such as Django-Registration: How to prevent logged in user from registering?, however I've tried the solution here, and it does not work for me.
I've searched through the Django Documentation, Django Girls and other websites that offer tutorials for learning Django.
Here's my views.py for the log in:
def login_view(request): # Login View to begin user session
print(request.user.is_authenticated())
if request.method == 'POST':
form = UserLogInForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
print(request.user.is_authenticated())
return HttpResponseRedirect('/')
else:
form = UserLogInForm()
return render(request, 'login.html', {'form': form})
else:
form = UserLogInForm()
return render(request, 'login.html', {'form': form})
and the sign up:
class signup_view(View):
form_class = UserSignUpForm
template_name = 'signup.html'
# Blank form is requested
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
# Form is filled in and posted to DB - Process the Data
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
# Further checks before committing object to the DB
# Cleaned Data
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = User.objects.create_user(first_name=first_name,
last_name=last_name,
email=email,
username=username,
password=password
)
user.set_password(password)
user.save()
user = authenticate(email=email, username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect('/')
return render(request, self.template_name, {'form': form})
If anybody knows any solutions then that would be amazing, thank you.
Since you are using a class-based view, you can use the UserPassesTestMixin and in the check method test that the user is anonymous:
class signup_view(UserPassesTestMixin, View):
...
def test_func(self):
return self.request.user.is_anonymous()
You can do a similar thing for the other view using the #user_passes_test decorator.
i guess you can add a middleware something like this :
your_app/middlewares/user_restriction_middleware.py
and that files be like:
class UserRestrictionMiddleware:
def process_request(self, request):
if request.user.is_authenticated():
request_path = request.path_info
if request_path.startswith('/login/') or request_path.startswith('/register/') :
return HttpResponseRedirect('.... to whereever you want...')
add this to your settings.py's MIDDLEWARE_CLASSES like :
'your_app.middlewares.user_restriction_middleware.UserRestrictionMiddleware',
Add this code before the POST request form .
class login(request):
if request.user.is_authenticated:
return redirect('app_name_space_name:your_url_name_to_send_authenticated_user_to')
#Your codes here

Categories