Sometimes you want to modify Django signup forms to include more data fields. In this tutorial, I have a fictional app called "SpyBook", a social network for secret operatives. At launch there are only two types of users, "Spy" and "Driver". Users need to be able to choose which one they are.
Our example will build off code from my Cookiecutter Django project, but should be portable to any project using Django Allauth.
Step 1: Tell Django-Allauth to Use A Customized Signup Form
At the bottom of config/settings/base.py
, past in the following code snippet:
# Control the forms that django-allauth uses
ACCOUNT_FORMS = {
"login": "allauth.account.forms.LoginForm",
"add_email": "allauth.account.forms.AddEmailForm",
"change_password": "allauth.account.forms.ChangePasswordForm",
"set_password": "allauth.account.forms.SetPasswordForm",
"reset_password": "allauth.account.forms.ResetPasswordForm",
"reset_password_from_key": "allauth.account.forms.ResetPasswordKeyForm",
"disconnect": "allauth.socialaccount.forms.DisconnectForm",
# Use our custom signup form
"signup": "spybook.users.forms.SpyBookSignupForm",
}
Step 2: Import Django Forms
In <yourprojectname>/users/forms.py
, Cookiecutter Django imports django.contrib.auth.forms
as forms
. This is a namespace problem since typically django.forms
is normally imported as plain forms
. To address that, let's just import django.forms
under a different namespace:
# Importing django.forms under a special namespace because of my old mistake
from django import forms as d_forms
Step 3: Import django-allauth's SignUp Form
Right under that forms import, get the SignUpForm
:
from allauth.account.forms import SignupForm
Step 4: Write Our Custom SignUp Form
Rather than write out a long explanation, I'll just comment every line of code.
# SpyBookSignupForm inherits from django-allauth's SignupForm
class SpyBookSignupForm(SignupForm):
# Specify a choice field that matches the choice field on our user model
type = d_forms.ChoiceField(choices=[("SPY", "Spy"), ("DRIVER", "Driver")])
# Override the init method
def __init__(self, *args, **kwargs):
# Call the init of the parent class
super().__init__(*args, **kwargs)
# Remove autofocus because it is in the wrong place
del self.fields["username"].widget.attrs["autofocus"]
# Put in custom signup logic
def custom_signup(self, request, user):
# Set the user's type from the form reponse
user.type = self.cleaned_data["type"]
# Save the user's type to their database record
user.save()
I wrote this out on my live stream, which you can watch on my youtube and twitch channels. I'll also be putting together a short video presentation of how this works. Of course, the code for this can be found on GitHub.
If you want to learn all kinds of advanced tricks and tips, take a look at my ice-cream themed book and course on Django Best Practices.
Top comments (1)
Now that the default signup form has been extended, how can you then add the "spy" dropdown to the admin panel?