Django cannot login user after registration - django

The app has a basic registration form. I am trying to authenticate users after they fill it out. However, I'm unable to authenticate them. Am I going about this in the correct way?
Here is the view:
def registration(request):
if request.method == "POST":
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = request.user
password1 = form.cleaned_data['password1']
#this works
try:
validate_password(password1, user)
except ValidationError as e:
form.add_error('password1', e)
return render(request, 'register.html', {'form': form})
profile = form.save(commit=False)
profile.save()
user = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password1'])
# this login not working, user is never authenticated
login(request, user)
return redirect('agree')
else:
raise ValidationError("Form is not valid. Try Again.")
else:
form = CustomUserCreationForm()
return render(request, 'register.html', {'form': form}).
Here is the forms.py. The model here is just the Django base user model.
class CustomUserCreationForm(forms.ModelForm):
username = forms.CharField(label='Username', widget=forms.TextInput(attrs={'class': "form-control"}))
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class': "form-control"}))
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput(attrs={'class': "form-control"}))
class Meta:
model = User
fields = ['username']
def clean_password(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords do not match")
return password2
def save(self, commit=True):
user = super(CustomUserCreationForm, self).save(commit=False)
user.username = self.cleaned_data['username']
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
User never gets registered and authenticated.

For authenticate() method, you need to pass request(reference authenticate() method in django backend). For example:
authenticate(request, username=form.cleaned_data['username'], password=form.cleaned_data['password1'])
Also why do you need authenticate method as you already have the user object:
profile = form.save() # <-- Its an user instance, name of the variable should be user
login(request, profile, backend='django.contrib.auth.backends.ModelBackend')
return redirect('agree')
Finally, you implementation looks bit fishy, why are you using user=request.user, is the user already logged in? I think this part of code is unnecessary:
user = request.user
password1 = form.cleaned_data['password1']
try:
validate_password(password1, user)
except ValidationError as e:
form.add_error('password1', e)
return render(request, 'register.html', {'form': form})

Related

clean(self) method is not called when if form.is_valid()

I have a RegisterUserForm that is bound to a CustomUser (that extends AbstractUser). Before I save the user, I want to check password1 and password2 if they are equal but the clean(self) method is not called. the user is created even if the passwords are not the same.
I have read a lot of questions and tried a lot of things but couldn't find an answer. My code is below
I tried adding an init and a save method but still does not work.
class RegisterUserForm(forms.ModelForm):
password1=forms.CharField(label=_("password"), min_length=4)
password2=forms.CharField(label=_("repeat password"), min_length=4)
class Meta:
model = CustomUser
fields = ('first_name', 'last_name', 'email', 'password1','password2')
def save(self, *args, **kwargs):
self.full_clean()
return super().save(*args, **kwargs)
def clean(self):
cleaned_data = super().clean()
print("clean is called")
password1 = form.cleaned_data.get("password1")
password2 = form.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise ValidationError('password_mismatch')
return self.cleaned_data
and my view is
def register(request):
if request.method=='POST':
form = RegisterUserForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.set_password(form.cleaned_data['password1'])
user.save()
email = user.email
messages.success(request, f'user with {email} created successfully')
return redirect('home')
else:
form = RegisterUserForm()
return render(request, 'users/register.html', {'form':form })

login in django using email or username (custom user model)

i am new to the django. i want that user is able to login using username or email. i am using custom user model. register page is working properly but in login while submiting login data i am getting errors.
my code is not working. i do not know how to get it working properly. please if anyone can help to get in working properly.thanks
//views.py
from django.shortcuts import render
from .forms import UserCreationForm,UserLoginForm
from django.http import HttpResponseRedirect
from django.contrib.auth import login,get_user_model, logout,authenticate
# Create your views here.
def base(request):
return render(request, 'articles/base.html')
def login(request,*args,**kwargs):
form=UserLoginForm(request.POST or None)
if form.is_valid():
user_obj=form.cleaned_data.get('user_obj')
print(user_obj)
username = user_obj['query']
password = user_obj['password']
user = authenticate(username=username, password=password)
if user is not None:
print("in login")
login(request, user)
return HttpResponseRedirect('/')
else:
return render(request, 'login1.html', {'form': form})
return render(request, 'articles/login1.html',{'form':form})
//forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.db.models import Q
from django.contrib.auth import get_user_model
User=get_user_model()
class UserCreationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model=User
fields=['username','email']
def clean_password(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserLoginForm(forms.Form):
query=forms.CharField(label='Username/Email')
password=forms.CharField(label='Password',widget=forms.PasswordInput)
def clean(self,*args,**kwargs):
query=self.cleaned_data.get('query')
password=self.cleaned_data.get('password')
user_qs_final=User.objects.filter(
Q(username__iexact=query)|
Q(email__iexact=query)
).distinct()
if not user_qs_final.exists() and user_qs_final!=1:
raise forms.ValidationError("Invalid credentials-user does not exits")
user_obj=user_qs_final.first()
if not user_obj.check_password(password):
raise forms.ValidationError("credential are wrong")
self.cleaned_data["user_obj"]=user_obj
return super(UserLoginForm,self).clean(*args,**kwargs)
currently i m gettin this error
TypeError: 'User' object is not subscriptable
The problem is with how you are accessing fields on your User object in the login method:
def login(request,*args,**kwargs):
form=UserLoginForm(request.POST or None)
if form.is_valid():
user_obj=form.cleaned_data.get('user_obj')
print(user_obj)
# username = user_obj['query']
# password = user_obj['password']
username = user_obj.username
password = user_obj.password
user = authenticate(username=username, password=password)
if user is not None:
print("in login")
login(request, user)
return HttpResponseRedirect('/')
else:
return render(request, 'login1.html', {'form': form})
return render(request, 'articles/login1.html',{'form':form})
When accessing the field values of a model, use . and not [].

django 2 Custom User: Attribute Error (password not passing/hashing properly)

I have implemented a custom user setup for django 2. However I can't seem to find out source of this error that occurs anytime I attempt to register.
AttributeError at /register/
'AnonymousUser' object has no attribute '_meta'
When I get this error, the password is passed without a hash and not saved to the db, while the other values pass through fine.
models.py
from django.db import models
from django.contrib.auth.models import BaseUserManager
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.utils.translation import ugettext_lazy as _
class MyUserManager(BaseUserManager):
def _create_user(self, email, password):
if not email:
raise ValueError('The Email must be set')
email = self.normalize_email(email)
user = self.model(email=email,)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password)
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, null=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
USERNAME_FIELD = 'email'
objects = MyUserManager()
def __str__(self):
return self.email
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import UserCreationForm, PasswordChangeForm
from django.contrib import messages
from . forms import RegisterForm
def home(request):
return render(request, 'authenticate/home.html', {})
def login_user(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
messages.success(request, ('Welcome Back'))
return redirect('home')
else:
messages.success(request, ('No account matches those credentials. Please try again.'))
return redirect('login')
else:
return render(request, 'authenticate/login.html', {})
def logout_user(request):
logout(request)
messages.success(request, ('Successfully logged out'))
return redirect('home')
def register_user(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
email = form.cleaned_data['email']
password = form.cleaned_data['password1']
user = authenticate(email=email, password=password)
login(request, user)
messages.success(request, ('Welcome to Keto2Go!'))
return redirect('home')
else:
form = RegisterForm()
context = {'form': form}
return render(request, 'authenticate/register.html', context)
def edit_profile(request):
if request.method == 'POST':
form = UserChangeForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
messages.success(request, ('You have updated your profile'))
return redirect('home')
else:
form = UserChangeForm(instance=request.user)
context = {'form': form}
return render(request, 'authenticate/edit_profile.html', context)
def change_password(request):
if request.method == 'POST':
form = PasswordChangeForm(data=request.POST, user=request.user)
if form.is_valid():
form.save()
messages.success(request, ('Your password has been updated.'))
return redirect('home')
else:
form = PasswordChangeForm(user=request.user)
context = {'form': form}
return render(request, 'authenticate/change_password.html', context)
forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from . models import User
class RegisterForm(forms.ModelForm):
password1 = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data and self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
class UserAdminCreationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
# Check that the two password entries match
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data and self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'password')
def clean_password(self):
return self.initial["password"]
In registration, you are trying to authenticate using keyword argument email but authenticate does not have any kwargs email, it takes username and password(Unless you override it in custom backend). So try like this(Just like your login_user view):
authenticate(request, username=email, password=password)
See in documentation for more details.
Also you password will not be saved in hash format, because you are directly saving it to Database using save method without using set_password. You need to update the save method in Registration form(Just like your UserAdminCreationForm)
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user

Facing an error for my custom login

Good day, I have the following two questions:
1) I'm using a custom login as shown on the django docs, but however I'm receiving an error when trying to save a new user.
This is my forms.py:
class UserCreationForm(forms.ModelForm):
"""
A form for creating a user, with no privileges.
Includes all the required fields, plus a repeated password.
"""
password1 = forms.CharField(label=_("Mot de passe"), widget=forms.PasswordInput)
password2 = forms.CharField(
label=_("Confirmer le mote de passe"),
widget=forms.PasswordInput,
help_text=_("Les deux mots de passe, doivent etre identique."))
class Meta:
model = IfasicUser
fields = ("email",)
def clean_email(self):
email = self.cleaned_data.get('email')
email_base, provider = email.split("#")
domain, extension = provider.split(".")
if not domain == "ifasic":
raise forms.ValidationError("domain doesn't exist")
if not extension == "cd":
raise forms.ValidationError("Utilisateur non identifie, reessayer.")
return email
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Les deux mots de passe, doivent etre identiques.")
return self.clean_password2
# TODO: make sure a student email must contains a student number as part of it.
# def validate_email(email):
# if '#' not in email:
# raise ValidationError('Invalid email. # not found')
# if '.' not in email:
# raise ValidationError('Invalid email. Incorrect domain?')
#
# # lowercase domain
# name, domain = email.split('#')
# email = '#'.join([name, domain.lower()])
# return email
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""
A form for updating a user. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField(
label=_("Password"),
help_text=_("Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using this form."))
class Meta:
model = IfasicUser
fields = '__all__'
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class MyAuthenticationForm(AuthenticationForm):
"""
A custom authentication form that extends the base AuthenticationForm
and overrides the username field to set it to an EmailField.
"""
username = forms.EmailField()
2) I would like to redirect a user to his content manager systems depending on the flag is_staff.
This is my attempted code. but with no results:
class AdminLogin(generic.TemplateView):
model = models.Staff
template_name = 'registration/login.html'
#sensitive_post_parameters()
#csrf_protect
#never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.POST.get(redirect_field_name,
request.GET.get(redirect_field_name, ''))
if request.method == "POST":
form = authentication_form(request, data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
# here where to redirect the user
if request.user is not None:
if request.user.is_active and request.user.is_staff:
redirect_to = 'home'
print(u'the request request.user')
# if Student.filter(user=request.user).exists():
# ...
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
if current_app is not None:
request.current_app = current_app
return TemplateResponse(request, template_name, context)
Any help will be appreciated.
1) The KeyError is for password as you are using password1 and password2. One solution would be to make the fields password and then password_confirm. This happens because you are using the ModelForm, so you a password field in IfasicUseralready.
2) Right after you set the redirect_to for the user you have another if statement that might be getting triggered and overwriting the redirect_to value. So in this case, if the user is_staff and also a student, then they would redirect to wherever the students go after login.

Django KeyError at /register/

I have a registration that let users register and i'm having difficulty fixing it.
The problem is when a user submits a single field instead of the whole form for example an email . I get this error
KeyError at /register/
password
Request Method: POST
Request URL: http://127.0.0.1:8000/register/
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in _get_errors
115. self.full_clean()
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in full_clean
271. self._clean_form()
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in _clean_form
299. self.cleaned_data = self.clean()
File "C:\o\17\mysite\pet\forms.py" in clean
31. if self.cleaned_data['password'] != self.cleaned_data['password1']:
Exception Type: KeyError at /register/
Exception Value: password
I tried to fix this solution using if . If user has a submitted a username or any other required field , process the form otherwise redisplay the original form.
but I still get the same error.
This is my edited views.py (at the bottom of the page is my original RegistrationForm)
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
if request.method =='POST':
form = UserRegistration(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
if username:
email=form.cleaned_data['email']
if email:
password=form.cleaned_data['password']
if password:
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': UserRegistration()})
How can I fix this error and also how could I display an error message on the other fields that the user didn't fill out like "Error Missing Field , Please Fill this Field".
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
if request.method =='POST':
form = UserRegistration(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': UserRegistration()})
My forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
name = forms.CharField()
email = forms.EmailField()
birthday = forms.DateField(widget=extras.SelectDateWidget(years=range(1950, 2012)))
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
password1 = forms.CharField(
label=(u'Verify Password'),
widget = forms.PasswordInput(render_value=False)
)
def clean_username(self):
username = self.cleaned_data['username']
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
"That user is already taken , please select another ")
def clean(self):
if self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
My models.py
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100, blank=True)
birthday = models.DateField(blank=True,null=True)
def __unicode__(self):
return self.name
Problem is with your clean(). In clean(), you are trying to access field password on form's cleaned_data. password will only be available on cleaned_data if the user has filled this field. So, you must check that password is there in cleaned_data before trying to access it.
Changing your clean():
def clean(self):
if 'password' in self.cleaned_data and 'password1' in self.cleaned_data and self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
You can provide a keyword argument error_messages on form field for showing error message like "Error Missing Field , Please Fill this Field".
class SomeForm(forms.Form):
name = forms.CharField(error_messages={'required':'Error Missing Field , Please Fill this Field'})
There is a bug in your view.
is_valid() populates errors on the form but this same form instance must be sent to the template so that you can access the errors on the form's fields.
But in your view, you have only one call to render() which gets called even in case of an invalid form on a post request. And in this render(), you are creating a new instance of form. So, this new form which you are sending to template will not have any errors.
So, making slight modification to your view:
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
form = UserRegistration() #This will be used in GET request
if request.method =='POST':
form = UserRegistration(request.POST) #This will be used in POST request
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': form})
Notice in your view, I have added form=UserRegistration() before checking if its POST request, and have added the comment at two places where we are instantiating UserRegistration. And then in render(), you should send this form.
Then your {{form.username.errors}} will work.
I just modified your forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
name = forms.CharField()
email = forms.EmailField()
birthday = forms.DateField(widget=extras.SelectDateWidget(years=range(1950, 2012)))
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
password1 = forms.CharField(
label=(u'Verify Password'),
widget = forms.PasswordInput(render_value=False)
)
def clean(self):
cleaned_data = super(UserRegistration, self).clean()
username = cleaned_data.get("username")
password = cleaned_data.get("password")
password1 = cleaned_data.get("password1")
#check if username exist
user = User.objects.filter(username=username)
if user:
raise forms.ValidationError(
"That user is already taken , please select another ")
#check password
if password != password1:
raise forms.ValidationError(
"Your current and confirm password do not match.")
return cleaned_data