In this tutorial I will cover a few strategies to create Django user sign up/registration. Usually I implement it from
scratch. You will see it’s very straightforward.
For the examples I will use an empty Django project named mysite. Inside the mysite folder I created an app
named core. So every time you see mysite and/or core, change to the suitable project name and app name.
A brief summary of what you are going to find here:
The most simple way to implement a user sign up is by using the UserCreationForm as it is. This strategy is suitable
in case you are using the default Django user, using username to authenticate and is interested only in setting the
username and password upon sign up.
urls.py
views.py
signup.html
Basically what we are doing here is handling the UserCreationForm processing. Business as usual. After the code reach
form.save(), the user is created. But here we need to take a step further: manually authenticate the user. You could
redirect the user to the login page, but performing the authentication is good for the user experience.
In order to perform the authentication, we need to grab the raw password from the input that came from POST. The
user.password stores the hash, and we can’t use it directly to authenticate.
If the authenticate() function is executed successfully (in this case it will always return a success), it will
a user instance (meaning the username and password matches), we can now securely log the user in. It’s done by
calling the login() function, passing the request and the user instance as parameter. After that, simply
redirect the user to wherever you want.
If you want more control over the signup.html form, you can extract the fields in a for loop:
So, what if I wanted to also get the user’s email address and full name upon sign up?
This strategy will work if you are using the Django user as it is, or if you have extended it using the AbstractUser
or AbstractBaseUser. If you extended the Django user using a Profile model, hold tight, we will get there too.
Now we need a step further, we have to extend the UserCreationForm.
forms.py
Now in the view, just change the form class to use our new SignUpForm.
views.py
It will look like this:
By the way, if you are wondering about the template, I’m using the same signup.html template from the previous
example.
With some tweaks we can also make it work using a profile model. Consider the model definition:
models.py
In this particular case, the profile is created using a Signal. It’s not mandatory, but usually it is a good way to
implement it. You can learn more about extending the user model in this post.
Let’s say we want to also get the birth_date of the user upon sign up. First, let’s update the model form:
forms.py
This form won’t save automatically the birth_date on form.save(). Instead, we have to handle it manually:
views.py
Because of the Signal handling the Profile creation, we have a synchronism issue here. It is easily solved by calling
the user.refresh_from_db() method. This will cause a hard refresh from the database, which will retrieve the profile
instance.
If you don’t call user.refresh_from_db(), when you try to access the user.profile, it will return None.
After refreshing it user model, set the cleaned data to the fields that matter, and save the user model. The user save
will trigger the profile save as well, that’s why you don’t need to call user.profile.save(), instead you call just
user.save().
I updated the birth_date directly in the view, but in case you are dealing with a bigger amount of fields in the
profile model, I would suggest creating two forms (say, UserForm and ProfileForm), and process both at once.
Check this gist for an example.
This one requires a more complicated setup. Because you know, you need to configure email, need some extra fields,
unique links with expiration date, and stuff like that.
I have already published in great detail each one of those parts, so in this post I will just put the pieces together.
For testing purpose, I will be using the console email backend, to debug the code:
Create a field to determine if the email is confirmed or not:
models.py
In an previous article I explained how to make use of some Django internal apis to create one time link. You can read
more about it here: How to Create a One Time Link (in case
you want to learn more how it works).
For our use case, create a new module named tokens.py.
tokens.py
We basically extended the PasswordResetTokenGenerator to create a unique token generator to confirm email addresses.
This make use of your project’s SECRET_KEY, so it is a pretty safe and reliable method.
Now we need to enforce the email registration on sign up.
forms.py
In the view processing we will no longer authenticate the user, instead we will email him/her the account activation
email:
views.py
Basically this is the same strategy for password reset. Notice that I’m changing the user.is_active to False, so
the user can’t log in before confirming the email address. After that, we send the email for the user. See below
the contents of the email template.
account_activation_email.html
And here is the routes you will need:
urls.py
The account_activation_sent view is a simple HTML template:
This page is showed right after the user submit the sign up form. Then, at the same time, the user will receive an
email with the link:
By clicking in the link, the user is sent to the activate view:
views.py
Here we do all the magic, checking if the user exists, if the token is valid. If everything checks, we switch the flags
is_active and email_confirmed to True and log the user in.
By changing the value of the email_confirmed field, it will cause the link to be invalidated.
That’s it! I hope you enjoyed this post. In a future post I can explore the third party libraries that help the
registration process. But usually I prefer to implement it by myself, and avoid an extra dependency.
All the four examples are available on GitHub in the same repository: