Django : authenticate() is not working for users created by register page, but working for those users who were created by admin

Question:

I want to make a register/login API for users.
Problem is like this :
If I create user via admin site, login is working properly.

If I create user via register page made by me, login isn’t working.(authenticate() function is returning None, even though that user is still in user table.)

I go to admin site, go to the link to change password and give the same password again. After that I can login successfully.

I think problem is either in saving password or login.
I have crossed checked a lot but couldn’t figure out.
I am giving all files. You may go through important code.

models.py

from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime

class Recruiter(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    company_name = models.CharField(max_length=120)
    HR_office_number = models.CharField(max_length=15)
    HR_mobile_number = models.CharField(max_length=15)

def __str__(self):
    return self.user.username

forms.py

from django import forms
from .models import Recruiter, User
from django.core.exceptions import ValidationError

class UserForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput(), max_length=128)
    confirm_password = forms.CharField(widget=forms.PasswordInput(), max_length=128)
    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'username', 'email']

    def __init__(self, *args, **kwargs):
        super(UserForm, self).__init__(*args, **kwargs)
        self.fields['first_name'].required = True
        self.fields['last_name'].required = True
        self.fields['email'].required = True
        self.fields['username'].help_text = None

    def clean_confirm_password(self):
        password1 = self.cleaned_data.get('password')
        password2 = self.cleaned_data.get('confirm_password')
        if not (password1 and password2):
            raise forms.ValidationError("You must confirm your password")
        elif password1 != password2:
            raise forms.ValidationError("Your passwords do not match")
        return password1


class RecruiterForm(forms.ModelForm):
    class Meta:
        model = Recruiter
        fields = ('company_name', 'HR_mobile_number', 'HR_office_number')

views.py

from django.shortcuts import render
from django.contrib.auth.models import User
from .models import Recruiter
from .forms import RecruiterForm, UserForm, RecruiterLoginForm
from django.urls import reverse
from django.http import HttpResponse,HttpResponseRedirect
from django.db import IntegrityError
from django.contrib.auth import authenticate, login, logout

def register(request):
    context = request.POST
    registered = False

    if request.method == 'POST':
        user_form = UserForm(data=request.POST)
        recruiter_form = RecruiterForm(data=request.POST)
        if user_form.is_valid() and recruiter_form.is_valid():
            user = user_form.save()
            try:
                user.set_password(user.password)
                user.save()
            except IntegrityError as e:
                user.delete()
                return HttpResponse(e.message)
            try:
                recruiter = recruiter_form.save(commit=False)
                recruiter.user = user
                recruiter.save()
            except IntegrityError as e:
                recruiter.delete()
                return HttpResponse(e.message)
            registered = True
        else:
            pass
            #print form.errors
    else:
        recruiter_form = RecruiterForm()
        user_form = UserForm()

    return render(request, 'recruiter/register.html', {'user_form':user_form,
                'recruiter_form':recruiter_form, 'registered':registered}, context)



def login_recruiter(request):
    context = request.POST
    if request.user.is_authenticated():
        return HttpResponse("Logged in")
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        print user
        if user:
            if user.is_active:
                login(request, user)
                return HttpResponse("Success")
            else:
                return HttpResponse("Not active")
        else:
            return HttpResponse("Invalid")
    else:
        return render(request, 'recruiter/login_recruiter.html', {}, context)

register.html

{% if registered %}
    <h1>Registered</h1><br />
{% else %}
<form id="user_form" method="post" action="{% url 'recruiter:register' %}" enctype="multipart/form-data">
    {% csrf_token %}
    {{ user_form.as_p}}
    {{ recruiter_form.as_p}}
    <input type="submit" name="submit" value="Register" />
</form>
{% endif %}

login_recruiter.html

<form id="login_form" method="post" action="{% url 'recruiter:login_recruiter' %}">
        {% csrf_token %}
        Username: <input type="text" name="username" value="" size="120" />
        <br />
        Password: <input type="password" name="password" value="" size="120" />
        <br />
        <input type="submit" value="submit" />
</form>
Asked By: Chaitanya Patel

||

Answers:

The issue is in how you set the password. You’ve excluded the password from the list of fields on the model form, so it is not set on save. So doing user.set_password(user.password) is effectively setting the password to the hash of None. Instead, do this:

user = user_form.save(commit=False)
user.set_password(user_form.cleaned_data['password']
user.save()

Note that even in your original code there was no way setting the password could cause IntegrityError, so that try/except was unnecessary; it’s even more so now, so you should remove it.

Answered By: Daniel Roseman

Use the below code to solve it..

def register(request, template_name="registration/register.html"):
    if request.method == "POST":
        postdata = request.POST.copy()
        username = postdata.get('username', '')
        email = postdata.get('email', '')
        password = postdata.get('password', '')

        # check if user does not exist
        if User.objects.filter(username=username).exists():
            username_unique_error = True

        if User.objects.filter(email=email).exists():
            email_unique_error = True

        else :
            create_new_user = User.objects.create_user(username, email, password)
            create_new_user.save()
            user = authenticate(username=username, password=password)
            login(request, user)
            if create_new_user is not None:
                if create_new_user.is_active:
                    return HttpResponseRedirect('/profile')
                else:
                    print("The password is valid, but the account has been disabled!")


    return  render(request, template_name, locals())


def log_in(request, template_name="registration/login.html"):
    page_title = "Login"
    if request.method == "POST":
        postdata = request.POST.copy()
        username = postdata.get('username', '')
        password = postdata.get('password', '')

        try:
            user = authenticate(username=username, password=password)
            login(request, user)

            return HttpResponseRedirect('/profile')
        except :
            error = True

    return render(request, template_name, locals())

Password field display

When we create a user by "register" page, then it saves the raw password. But Django does not store raw passwords.

I am also facing the same issue. But I tried:

user = User.objects.create_user(username=username,password=password)
user.save()

instead of

user = User.objects.create_user(username,password)
Answered By: Prafull Epili
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.