Search code examples
pythondjangoauthenticationdjango-authenticationdjango-users

Unable to change password in Django with custom user model


I have been trying to get the default Django authentication system to work with custom users. I am able to create the user types, login and logout. However, when it comes to changing the password, I get logged out and then the password is not changed. I also tried to see if by resetting the password through email anything would change, yet I still can't change the password. My app name is account.

This is my custom user model, I tried adding the set_password method to make sure it could change the password. I have only included the user manager for readability :

class UserManager(BaseUserManager):
    def _create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError("The given email must be set")
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", False)
        extra_fields.setdefault("is_superuser", False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", 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, **extra_fields)

class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(_("email address"), unique=True)
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []
    objects = UserManager()

    def set_password(self, raw_password):
        self.password = make_password(raw_password)
        self._password = raw_password


class Student(CustomUser):
    student = StudentManager()

    class Meta:
        proxy = True


class Teacher(CustomUser):
    teacher = TeacherManager()

    class Meta:
        proxy = True

For the rest I use all the default Django authentication urls and views but i have tried modifying the password change view to make sure I don't log out, however the issue persists :

urlpatterns = [
    path('password_change/', CustomPasswordChangeView.as_view(), name='password_change')
    path('', include('django.contrib.auth.urls')),   
]

CustomPasswordChangeView :

class CustomPasswordChangeView(auth.views.PasswordChangeView):
    template_name = "registration/password_change_form.html"
    success_url = reverse_lazy("password_change_done")

    def form_valid(self, form):
        response = super().form_valid(form)
        update_session_auth_hash(self.request, form.user)
        return response

Even with the form_valid method changed, I am still logged out when the form is submitted. I enter the old email and password and I am redirected to the password_change_done view, and the password is not changed.

Finally, I have made sure to add the following to the settings : AUTH_USER_MODEL = "account.CustomUser"


Solution

  • After the comments telling me the problem wasn't reproducible I found the issue : a save function I hadn't included in the problem.

        def save(self, *args, **kwargs):
        if not self.pk:
            super().save(*args, **kwargs)
            try:
                self.base_group.user_set.add(self)
            except:
                pass
    

    This was supposed to make sure a user always belonged to the right group, however it interfered with the password change. Thank you to all of those who commented and answered.