Search code examples
pythondjangodjango-users

Issue signing up new users in Django


I have the following signup flow in an app using Django 1.11-

accounts/views.py:

from .forms import UserForm

def sign_up(request):
    if request.method == "POST":
        form = UserForm(request.POST)
        if form.is_valid():
            user = form.save()
            return redirect('index')
    else:
        form = UserForm()
    return render(request, 'signup.html', {'form': form})

accounts/forms.py:

from django.forms import ModelForm
from django.contrib.auth.models import User

class UserForm(ModelForm):
    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'username', 'email', 'password']

It does appear to "register" a new user, in that it creates a new user in the database. The issue is I cannot login with that newly created user, the username/pw combo does not match. Going into the database I see the newly created users, but the password is in plain text: "password". But the first user I created through the command line, python manage.py createsuperuser has a salted hash as the password like pasdfhjasf8234jk324hgsdfa8df89asdf987 and I can login correctly using the password I made for it, ie "password".

How do I save new users using my ModelForm where Django knows to correctly store the password as a salted hash?


Solution

  • You can not set the password through the boilerplate code in the ModelForm, you need to use .set_password(..) [Django-doc] to hash the password:

    class UserForm(ModelForm):
    
        class Meta:
            model = User
            fields = ['first_name', 'last_name', 'username', 'email', 'password']
    
        def save(self, commit=True):
            user = super().save(commit=False)
            user.set_password(self.cleaned_data['password'])
            if commit:
                user.save()
            return user

    Django however has already a UserCreationForm [Django-doc] that implements this. It will use two form fields to validate that the user has entered the same password twice. We can thus subclass the UserCreationForm:

    from django.contrib.auth.forms import UserCreationForm
    
    class UserForm(UserCreationForm):
    
        class Meta:
            model = User
            fields = ['first_name', 'last_name', 'username', 'email']