In this tutorial we will cover advanced user registration view with Django.
First let's build basic sign up view then we are going to add some extra fields and confirmation mail function to make it advanced.
I am assuming that you already created your Django project.
Basic Registration
Django authentication framework provides a form named UserCreationForm (which inherits from ModelForm class) to handle the creation of new users. It has three fields namely username, password1 and password2 (for password confirmation).
cleaned_data is holding the validated form data and authenticate() method takes credentials as keyword arguments, username and password for the default case, checks them against each authentication backend, and returns a User object if the credentials are valid for a backend.
Once user is verified, login() method takes an HttpRequest object and a User object and saves the user’s ID in the session, using Django’s session framework. Finally, redirect() method is basically redirecting the logged in user to home URL.
Last step for basic registration, in your signup.html template:
<h2>Sign up Form</h2><formmethod="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<smallstyle="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<pstyle="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<buttontype="submit">Sign up</button></form>
We are displaying each field in our form with help texts to avoid errors. If any errors occurs while registration it is nice to display user what causes these errors.
Registration with extra fields
What if we want register user with email or username? So, create forms.py and extend the UserCreationForm.
That's it! Now, user can register by his/her username and email as well.
Registration with Profile Model
In my view, this is the best and recommended way to implement registration system in your Django application. We are going to use Django Signals to create a user profile right after user registered. So, take a look models.py
With the @receiver decorator, we can link a signal with a function. So, every time that a User model instance ends to run its save() method (or when user register ends), the update_profile_signal will start to work right after user saved.
sender - The model class.
instance - The actual instance being saved.
created - A boolean; True if a new record was created.
Well, we want from user to enter his/her information into extra fields above to complete registration. Let's update forms.py :
We are using refresh_from_db() method to handle synchronism issue, basically reloading the database after the signal, so by this method our profile instance will load. Once profile instance loaded, set the cleaned data to the fields and save the user model.
Registration with Confirmation Mail
At this stage, we are going to configure email backend to send confirmation links. Let's test it on console for this tutorial.
PasswordResetTokenGenerator is generating a token without persisting it in the database so, we extended it to create a unique token generator to confirm registration or email address. This make use of your project’s SECRET_KEY, so it is a secure and reliable method.
Once user clicked the link, it will no longer be valid.The default value for the PASSWORD_RESET_TIMEOUT_DAYS is 7 days but you can change its value in the settings.py .
and in views.py we will no longer authenticate the user, instead we will send activation link.
views.py
defsignup_view(request):ifrequest.method=='POST':form=SignUpForm(request.POST)ifform.is_valid():user=form.save()user.refresh_from_db()user.profile.first_name=form.cleaned_data.get('first_name')user.profile.last_name=form.cleaned_data.get('last_name')user.profile.email=form.cleaned_data.get('email')# user can't login until link confirmed
user.is_active=Falseuser.save()current_site=get_current_site(request)subject='Please Activate Your Account'# load a template like get_template()
# and calls its render() method immediately.
message=render_to_string('activation_request.html',{'user':user,'domain':current_site.domain,'uid':urlsafe_base64_encode(force_bytes(user.pk)),# method will generate a hash value with user related data
'token':account_activation_token.make_token(user),})user.email_user(subject,message)returnredirect('activation_sent')else:form=SignUpForm()returnrender(request,'signup.html',{'form':form})
So basically we are generating activation url with user related data and sending it. Note that, we are setting user.is_active = False that means user can't login until he/she confirmed the registration.
Now, create activation_request.html template which will ask from user to confirm the link (This will show up in your console).
Create one more template named activation_sent.html. This will inform user that to check his/her mail to confirm registration
<h3>Activation link sent! Please check your console or mail.</h3>
When user clicked the link, we have to check if the user exists and the token is valid.
defactivate(request,uidb64,token):try:uid=force_text(urlsafe_base64_decode(uidb64))user=User.objects.get(pk=uid)except (TypeError,ValueError,OverflowError,User.DoesNotExist):user=None# checking if the user exists, if the token is valid.
ifuserisnotNoneandaccount_activation_token.check_token(user,token):# if valid set active true
user.is_active=True# set signup_confirmation true
user.profile.signup_confirmation=Trueuser.save()login(request,user)returnredirect('home')else:returnrender(request,'activation_invalid.html')
Once registration confirmed, user becomes active and be able to login.
Full code of views.py:
fromdjango.contrib.authimportlogin,authenticatefromdjango.shortcutsimportrender,redirect,get_object_or_404,HttpResponseRedirectfromdjango.contrib.sites.shortcutsimportget_current_sitefromdjango.utils.encodingimportforce_textfromdjango.contrib.auth.modelsimportUserfromdjango.dbimportIntegrityErrorfromdjango.utils.httpimporturlsafe_base64_decodefromdjango.utils.encodingimportforce_bytesfromdjango.utils.httpimporturlsafe_base64_encodefrom.tokensimportaccount_activation_tokenfromdjango.template.loaderimportrender_to_stringfrom.formsimportSignUpFormfrom.tokensimportaccount_activation_tokendefhome_view(request):returnrender(request,'home.html')defactivation_sent_view(request):returnrender(request,'activation_sent.html')defactivate(request,uidb64,token):try:uid=force_text(urlsafe_base64_decode(uidb64))user=User.objects.get(pk=uid)except (TypeError,ValueError,OverflowError,User.DoesNotExist):user=None# checking if the user exists, if the token is valid.
ifuserisnotNoneandaccount_activation_token.check_token(user,token):# if valid set active true
user.is_active=True# set signup_confirmation true
user.profile.signup_confirmation=Trueuser.save()login(request,user)returnredirect('home')else:returnrender(request,'activation_invalid.html')defsignup_view(request):ifrequest.method=='POST':form=SignUpForm(request.POST)ifform.is_valid():user=form.save()user.refresh_from_db()user.profile.first_name=form.cleaned_data.get('first_name')user.profile.last_name=form.cleaned_data.get('last_name')user.profile.email=form.cleaned_data.get('email')# user can't login until link confirmed
user.is_active=Falseuser.save()current_site=get_current_site(request)subject='Please Activate Your Account'# load a template like get_template()
# and calls its render() method immediately.
message=render_to_string('activation_request.html',{'user':user,'domain':current_site.domain,'uid':urlsafe_base64_encode(force_bytes(user.pk)),# method will generate a hash value with user related data
'token':account_activation_token.make_token(user),})user.email_user(subject,message)returnredirect('activation_sent')else:form=SignUpForm()returnrender(request,'signup.html',{'form':form})
Great! In this tutorial we used console to check our link but you can configure a production quality email service to send actual confirmation mail. My next tutorial will cover this topic so make sure you are following me on social media and check Reverse Python for more articles like this.