Extending and customizing django-allauth

Source : Pexels.com

In the previous tutorial, we learned about setting up and configuring some basic settings of django-allauth. If you have not yet read it, I recommend you read it here. You can proceed if you have completed the basic setup and configuration.

This article deals with customizing django-allauth signup forms, intervening in registration flow to add custom process and validations. Social logins and their customizations discussed in the next article.

Extending Signup Form or adding custom fields in django-allauth

One of the most common queries about allauth is about adding additional fields or custom fields to the signup form. You can extend the SignupForm class from allauth.account.forms. All you need to do is create a custom class pass the SignupForm to the custom class and define the custom fields and save it. Its vital to return the user object as it will be passed to other modules for validations. You also need to include ACCOUNT_FORMS variable in settings.py.

Let us see this using an example. In forms.py.

from allauth.account.forms import SignupForm
from django import forms
class CustomSignupForm(SignupForm):
first_name = forms.CharField(max_length=30, label='First Name')
last_name = forms.CharField(max_length=30, label='Last Name')
    def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
return user

In the above snippet CustomSignupFormis extended class which inherits all the features of SignupForm class and adds the necessary features. Here custom fields by the name first_nameand last_name are created and saved in using the signup module in the same class.

The ACCOUNT_FORMS in settings.py for the above code is

ACCOUNT_FORMS = {
'signup': 'YourProject.forms.CustomSignupForm',
}

Any other custom forms created can be extended in ACCOUNT_FORMS. The list is illustrated in the documentation.

Similarly, LoginForm UserForm AddEmailForm and others can be extended. However, remember that when you extend these forms and link them in settings.py. Do Not forget to pass the original form (For example SignupForm) as a parameter to your class and sometimes you might have to handle custom validations and return user or some other value. Please refer to the source code to follow the correct flow.

User Intervention and Custom validations

I recently encountered some good questions on stack overflow and on the repository issue section with regards to adding custom validations and intervening in the user registration flow. When researching for a solution and scanning through the documentation, I found the DefaultAccountAdapter very useful and indeed can be used to solve most of customization problems that a user might encounter while using django-allauth. I reproduce the answers and with some instructions below.

Example 1: Restricted List of email’s

After figuring out a way to store and fetch the restricted list, you can use the adapters and raise validation error in the registration form when a restricted email tries to register. Extend a DefaultAccountAdapter and override the clean_email method. Create an adapter.py in your project directory and extend the default adapter class.

from allauth.account.adapter import DefaultAccountAdapter
from django.forms import ValidationError
class RestrictEmailAdapter(DefaultAccountAdapter):
    def clean_email(self,email):
RestrictedList = ['Your restricted list goes here.']
if email in RestrictedList
raise ValidationError('You are restricted from registering. Please contact admin.')
return email

Finally, point the account adapter in settings.py to your extended class. ACCOUNT_ADAPTER = 'YourProject.adapter.RestrictEmailAdapter'

Example 2: Add a Maximum length to a username

As ACCOUNT_USERNAME_MAX_LENGTH does not exist in the allauth library, DefaultAccountAdaptercan be used to achieve this feature without much pain. Extend the the DefaultAccountAdapterclass and overriding the clean_username method. You need to also reference the clean_username once again after our custom validation to complete other inbuilt validations.

The Last sentence in the above paragraph is the key to work with DefaultAccountAdapter. You should never forget to reference the original module name for the module to complete other validations.

from allauth.account.adapter import DefaultAccountAdapter
from django.forms import ValidationError
class UsernameMaxAdapter(DefaultAccountAdapter):
    def clean_username(self, username):
if len(username) > 'Your Max Size':
raise ValidationError('Please enter a username value less than the current one')
return DefaultAccountAdapter.clean_username(self,username) # For other default validations.

Finally, point to the subclass in your settings.py
ACCOUNT_ADAPTER = 'YourProject.adapter.UsernameMaxAdapter'

You can refer to adapters.py file in the source code and extend other modules and add a process or change their flow. The modules such as populate_username, clean_password (which can be customized to restrict commonly used passwords) can have the custom process and flows without rewriting them.

DefaultAccountAdapter can be a potent tool if used in right circumstances to intervene in allauth's default process. allauth comes with a vast variety inbuilt settings, and they are here. You can also download the entire source code from the link in the references below.

References:
1. django-allauth documentation
2. stack overflow thread on Example 1
3. stack overflow thread on Example 2
4. adapters.py in allauth source code
5. Source code for this tutorial