loading...

Customizing Django Allauth Signup Forms

danielfeldroy profile image Daniel Feldroy Updated on ・2 min read

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.

Posted on by:

danielfeldroy profile

Daniel Feldroy

@danielfeldroy

Engineer and writer. Co-author of Django Crash Course & Two Scoops of Django, Husband of @audreyfeldroy 💘, father of Uma 🍼

Discussion

pic
Editor guide
 

Now that the default signup form has been extended, how can you then add the "spy" dropdown to the admin panel?