Problem when creating a super user

Hello everyone,

I’m facing an issue while creating my superuser using the following command: “python manage.py createsuperuser”.
There’s no problem when entering the username and email. However, my issue arises when entering the password.
As you can see in the image below, there’s a message in French indicating that the passwords are not identical. I added a “print” statement in my validators.py file because initially I didn’t understand why I was getting this error message when I was entering the same password twice.
Interestingly, when I create a basic user via an HTML page, I don’t encounter this problem.
Could someone kindly help me understand the root cause of this problem?
If you need additional screenshots, please feel free to ask.
Thank you for your assistance.
Best regards,

image

Are you using any custom code as part of this? (A custom User model perhaps? Or some other non-standard code? Even perhaps a custom “createsuperuser” command?) If so, please post the customized modules that are involved here.

Note: When posting code, templates, screen output, etc, try to avoid posting images. Copy/paste the text into the body of your message between lines of three backtick - ` characters. This means you’ll have a line of ```, then your code, then another line of ```.

Hello and thank you for taking the time to respond.
Here is the code that allows registering a basic user via an HTML page. I have no problem proceeding with user registration.
I’m a student, so there might be errors in my code, but I would appreciate your feedback on the code implementation.
Thanks again, and I look forward to reading your responses.

# validators.py
class ContainsLetterValidator:
    def validate(self, password1, user=None):
        if not any(char.isalpha() for char in password1):
            raise ValidationError('Votre mot de passe doit contenir au moins une lettre majuscule ou minuscule!',
                                  code='password_no_letters')

    def get_help_text(self):
        return 'Lettre majuscule ou minuscule!'


class ContainsNumberValidator:
    def validate(self, password1, user=None):
        if not any(char.isdigit() for char in password1):
            raise ValidationError('Le mot de passe doit contenir au moins un chiffre', code='password_no_numbers')

    def get_help_text(self):
        return 'Un chiffre '


class Password1Password2:
    def validate(self, password1, password2, user=None):
        if password1 != password2:
            print(password1, password2)
            raise ValidationError('Les mots de passe ne sont pas identiques !', code='passwords_not_identical')

    def get_help_text(self):
        return 'Mots de passe '
# forms.py
class SignupForm(UserCreationForm):
    username = forms.CharField(max_length=150, widget=forms.TextInput(attrs={'placeholder': 'Pseudo'}))
    email = forms.CharField(max_length=150, widget=forms.EmailInput(attrs={'placeholder': 'Email'}))
    password1 = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Mot de passe'}))
    password2 = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Confirmer le mot de passe'}))

    def clean_password2(self):
        cleaned_data = super().clean()
        password1 = cleaned_data.get('password1')

        validator1 = ContainsLetterValidator()
        validator1.validate(password1)

        validator2 = ContainsNumberValidator()
        validator2.validate(password1)

        password2 = cleaned_data.get('password2')
        validator3 = Password1Password2()
        validator3.validate(password1, password2)

    class Meta(UserCreationForm.Meta):
        model = get_user_model()
        fields = ('username', 'email', 'password1', 'password2')
# views.py
def signup_page(request):
    form = forms.SignupForm()
    if request.method == 'POST':
        form = forms.SignupForm(request.POST)
        if form.is_valid():
            user = form.save()
            # auto-login user
            login(request, user)
            return redirect(settings.LOGIN_REDIRECT_URL)
    return render(request, 'authentication/signup.html', context={'form': form})

You didn’t show that but I guess you set the AUTH_PASSWORD_VALIDATORS setting in your django settings, with the Password1Password2 validator in the list of validators. AUTH_PASSWORD_VALIDATORS are only validators for a single password; in your case, the Password1Password2 receives the password as first argument and the user as second argument (password2 in your case), thus leading to the password and username display in your print function call (as we can see in your initial post).

So, you should consider removing Password1Password2 from AUTH_PASSWORD_VALIDATORS so that superuser creation works.

As a side note, validation in your SignupForm is not correctly implemented:

clean_password2 method should be used for password2 validation only, but here you validate password1 as well.

Correct implementation would be:

  • call validator1 and validator2 in clean_password1
  • call validator3 in clean() method overide

To add to the previous response, a clean_<field> method must return the validated data.

From the docs at: Form and field validation | Django documentation | Django

The return value of this method replaces the existing value in cleaned_data , so it must be the field’s value from cleaned_data (even if this method didn’t change it) or a new cleaned value.

Just refactoring the validator calls would not fix the issue. The root problem here is that clean_password2 is not returning a value, which means that the password2 field is being set to None.

Also, if you look at the base “UserCreationForm”, you’ll see that password1 and password2 are not defined as model fields in the form - password1 and password2 are not saved in the database, only password.

@antoinehumbert
@KenWhitesell

Hello gentlemen,
I thank you for your responses. I will consider your suggestions and I will come back to give you updates regarding password validation.