I know there are hundreds of posts about that topic but, in all of them, there is something slightly different from my own program and I can't adapt it to my program because the Django way of handling password is such a mess that I understand nothing. A little help would be greatly appreciated, I thank you in advance.
So, when a new user registers, everything works perfectly but, somehow, the password is not saved in the database. When I go to the admin interface, it tells me that the password format is invalid or the hashag function is not known.
Here is my code :
Forms.py
class InscriptionForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'email', 'password']
widgets = {'username': forms.TextInput(attrs={'class': 'form-control'}),
'first_name': forms.TextInput(attrs={'class': 'form-control'}),
'last_name': forms.TextInput(attrs={'class': 'form-control'}),
'email': forms.EmailInput(attrs={'class': 'form-control'}),
'password': forms.PasswordInput(attrs={'class': 'form-control'})}
def clean_password(self):
password = self.cleaned_data['password']
try:
validate_password(password, user=self)
except forms.ValidationError:
self.add_error('password', password_validators_help_texts())
return password
Views.py
def inscription(request):
if request.method == "POST":
form = InscriptionForm(request.POST)
if form.is_valid():
new_user = form.save()
authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password'],)
login(request, new_user)
request.session['is_connected'] = True
return redirect(inscription_suite)
else:
form = InscriptionForm()
return render(request, 'inscription/inscription.html', {'form': form})
I already tried modifying the view like this :
def inscription(request):
if request.method == "POST":
form = InscriptionForm(request.POST)
if form.is_valid():
new_user = form.save(commit=False)
new_user.password = make_password(form.cleaned_data['password'])
authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password'],)
login(request, new_user)
new_user.save()
request.session['is_connected'] = True
return redirect(inscription_suite)
else:
form = InscriptionForm()
return render(request, 'inscription/inscription.html', {'form': form})
But it raises the following error ValueError at /inscription
Cannot force an update in save() with no primary key.
Can someone help me please ?
Thanks in advance !
You must save password using set_password().
def inscription(request):
if request.method == "POST":
form = InscriptionForm(request.POST)
if form.is_valid():
new_user = form.save(commit=False)
password = form.cleaned_data['password'] # get password
new_user.set_password(password) # set the password
new_user.save() # save the user
authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password'],)
login(request, new_user)
request.session['is_connected'] = True
return redirect(inscription_suite)
else:
form = InscriptionForm()
return render(request, 'inscription/inscription.html', {'form': form})
Related
I want to sign in to be able to use the site. However, I'm having a problem: 'LoginForm' object has no attribute 'cleaned_data'. Please tell me how can I solve it. I apologize in advance for my English
My forms.py
class LoginForm(forms.Form):
user_name = forms.CharField(max_length=20, widget=TextInput(attrs={'type':'text','class': 'form-control','placeholder': 'Input username'}))
passWord = forms.CharField(max_length=25, widget=TextInput(attrs={'type':'password','class': 'form-control','placeholder': 'Input password'}))
class Meta:
fields = ['user_name', 'passWord']
My views.py
def login_view(request):
template_name = 'main/login.html'
action_detail = ''
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid:
username = form.cleaned_data.get('user_name')
password = form.cleaned_data.get('passWord')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('/')
else:
action_detail = 'invalid username or password'
else:
form = LoginForm()
context={
'title': 'Login',
'form': form,
'action_detail': action_detail,
}
return render(request, template_name, context)
is_valid is a function.
https://docs.djangoproject.com/en/4.0/ref/forms/api/#django.forms.Form.is_valid
You should call it.
if form.is_valid():
I have created an abstract user model in Django. The user belongs to multiple services. When I register the user to database then the user has been register instead user_services. user_services are not stored in database while we register the new user.
models.py
class UserAbstract(AbstractUser):
user_services = models.ManyToManyField(UserServices, related_name='services', blank=True)
is_expert = models.BooleanField(default=False)
forms.py
class UserRegistrationForm(UserCreationForm):
class Meta:
model = UserAbstract
fields = [
'username',
'email',
'password1',
'password2',
'user_services',
'is_expert',
]
views.py
def Register(request):
if request.method == 'POST':
form = UserRegistrationForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
user = form.save()
if user is not None:
login(request, user)
messages.success(request, f'{username} account has been registered!')
return redirect('profile')
else:
messages.error(request, "Invalid username or password.")
else:
form = UserRegistrationForm()
return render(request, 'user/register.html', {'form': form})
I just need to add this line after save the user!
user = form.save()
user.user_services.set(services) # services
I have created an extended User model and a form to register it. Since the form is filled out by an admin and not a user, the UserCreationForm has a random password generator to fill out password1 and 2, then set new password. This is great for a new user, but every time an admin edits the user profile, it will set a new password. I've looked at a few dozen examples here and on big G but can't seem to find a usable solution to know if the user has a password set.
I am re-using this form for update view, which is where I don't want the random password to be generated again. I tried doing the same if statement check as the username but it doesn't work the same way as the auth\form.py user.set_password is looking for password1.
class EmployeeRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, widget=forms.EmailInput(attrs={'class': 'form-control mb-2',
'placeholder': 'Email address'}))
first_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control mb-2',
'placeholder': 'First name'}))
last_name = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control mb-2', 'placeholder': 'Last name'}))
password1 = None
password2 = None
class Meta:
model = User
fields = ['email', 'first_name', 'last_name']
def clean(self):
password = User.objects.make_random_password(length=10,
allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')
self.cleaned_data['password1'] = password
self.cleaned_data['password2'] = password
return super().clean()
def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if user.username == '':
if len(user.first_name.split()) and len(user.last_name.split()) > 1:
username = f'{"".join(user.first_name.split()[:2])}{"."}{"".join(user.last_name.split())}'
elif len(user.first_name.split()) > 1:
username = f'{"".join(user.first_name.split()[:2])}{"."}{user.last_name}'
elif len(user.last_name.split()) > 1:
username = f'{user.first_name}{"."}{"".join(user.last_name.split())}'
else:
username = f'{user.first_name}{"."}{user.last_name}'
username = username.lower()
user.username = username
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
Update
Here is the profile_edit view where I verify the details of an existing user and save changes made through the form.
#login_required()
def profile_edit(request, slug, *args, **kwargs):
"""
Used for updating the Employee profile
"""
employee = Employee.objects.get(slug=slug)
employee_user = User.objects.get(id=employee.user.id)
form = EmployeeForm(request.POST or None, request.FILES or None, instance=employee)
user_form = EmployeeRegistrationForm(request.POST or None, instance=employee_user)
if 'cancel' in request.POST:
return redirect('corehr:employees')
elif request.method == 'POST':
form = EmployeeForm(request.POST or None, request.FILES or None, instance=employee)
user_form = EmployeeRegistrationForm(request.POST or None, instance=employee_user)
if form.is_valid() and user_form.is_valid():
form.save(commit=False)
user_form.save()
form.save()
messages.success(request, f'{employee.get_full_name}{" was updated successfully."}')
return redirect(reverse_lazy('corehr:profile', kwargs={'slug': slug}))
else:
messages.error(request, 'Please correct the errors listed below')
else:
form = EmployeeForm(request.POST or None, request.FILES or None, instance=employee)
user_form = EmployeeRegistrationForm(request.POST or None, instance=employee_user)
context = {'form': form, 'user_form': user_form}
return render(request, 'coreHR/profile_edit.html', context)
I ended up taking the suggestions from Abdul and Ranu. The are both right, so I just created a UserUpdateForm to update the data rather to 're-create' the user again. It all works as smooth as ever.
class UserUpdateForm(forms.ModelForm):
class Meta:
model = User
fields = ['email', 'first_name', 'last_name']
widgets = {
'email': forms.EmailInput(attrs={'class': 'form-control mb-2'}),
'first_name': forms.TextInput(
attrs={'class': 'form-control mb-2'}),
'last_name': forms.TextInput(
attrs={'class': 'form-control mb-2'}),
}
I replaced the reference in the profile_edit view from EmployeeRegistrationForm to UserUpdateForm. This was so simple an I was busting my head trying to work around several complex solutions which were going against the basics.
I'm creating a user update form in my app. but every time when the form is submitted , it creates a new record and if you try submitting again will return Integrity Error(duplicate username that both are null).
ERROR message: django.db.utils.IntegrityError: UNIQUE constraint failed: auth_user.username
forms.py:
class UserChangeForm(forms.ModelForm):
class Meta:
model = User
fields = ['email', 'first_name', 'last_name']
def __init__(self, username, *args, **kwargs):
super(UserChangeForm, self).__init__(*args, **kwargs)
self.username = username
views.py:
def profile(request):
user = request.user
if request.method == 'POST':
user_form = UserChangeForm(user, request.POST)
if user_form.is_valid():
user_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('users:profile')
else:
email = request.user.email
first_name = request.user.first_name
last_name = request.user.last_name
user_form = UserChangeForm(user, initial={
'email': email,
'first_name': first_name,
'last_name': last_name
})
context = {
'user_form': user_form,
}
return render(request, 'users/profile.html', context)
you need to pass the user as instance in the if condition and in else too like this
def profile(request):
if request.method == 'POST':
user_form = UserChangeForm(request.POST , instance = request.user)
if user_form.is_valid():
user_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('users:profile')
else:
user_form = UserChangeForm(instance=request.user)
context = {
'user_form': user_form,
}
return render(request, 'users/profile.html', context)
I want logged in user redirect to index when they attempt to go to the register form.
I manage to do to that, but I can't validate the register form when the a user who is not logged in complete it.
I have a custom view for signup:
class SignupView(UserPassesTestMixin, FormView):
template_name = 'main/auth/register.html'
form_class = forms.UserCreationForm
def test_func(self):
self.request.user.is_authenticated
def handle_no_permission(self):
if self.request.user.is_authenticated:
return redirect('main:index')
return self.get(self.request)
def get_success_url(self):
redirect_to = self.request.GET.get`enter code here`('next', 'main:index')
return redirect_to
def form_valid(self, form):
response = super().form_valid(form)
form.save()
email = form.cleaned_data.get('email')
first_name = form.cleaned_data.get('first_name')
raw_password = form.cleaned_data.get('password1')
logger.info('Nuevo registro para email=%s a través de SignupView', email)
user = authenticate(email=email, password=raw_password)
login(self.request, user)
form.send_mail()
return response
methods
test_func(self) and handle_no_permission(self) are used to test if the user is authenticated
but I think the problem is in return self.get(self.request) I use it to load the form but when I submit the form with correct data, it POST it to validate it, but just reload it again. I suppose I have to call form_valid but I can't figure out how.
Any help would be appreciated!! Regards
You can use the dispatch method of django CBV. Like below.
class SignupView(UserPassesTestMixin, FormView):
template_name = 'main/auth/register.html'
form_class = forms.UserCreationForm
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
return redirect('main:index')
return super().dispatch(request, *args, **kwargs)
# other methods
This is function based views and its simple
views.py
to register
def register(request):
if request.user.is_authenticated:
return redirect(reverse('post_list'))
else:
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid():
new_user = user_form.save(commit=False)
new_user.set_password(
user_form.cleaned_data['password1']
)
new_user.save()
Profile.objects.create(user=new_user)
return render(
request,
'account/register_done.html',
{'new_user': new_user}
)
else:
user_form = UserRegistrationForm()
return render(
request,
'account/register.html',
{'user_form': user_form}
)
forms.py
class UserRegistrationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(attrs={
'class': 'myfieldclass',
'placeholder': 'Password ...',
'type': 'password',
'name': 'password'
}))
password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput(attrs={
'class': 'myfieldclass',
'placeholder': 'Repeat Password ...',
'type': 'password',
'name': 'password'
}))
username = forms.CharField(label='Username', widget=forms.TextInput(attrs={
'class': 'myfieldclass',
'placeholder': 'Username ...',
'type': 'text',
'name': 'username'
}))
email = forms.CharField(label='Email', widget=forms.EmailInput(attrs={
'class': 'myfieldclass',
'placeholder': 'Email ...',
'type': 'email',
'name': 'email'
}))
class Meta:
model = User
fields = ('username', 'email')
help_texts = {
'username': '',
}
def clean_password2(self):
cd = self.cleaned_data
if cd['password1'] != cd['password2']:
raise forms.ValidationError(
'Passwords dosent Matched.')
return cd['password2']