Modifying Django AllAuth Forms

Gavin Wiener
4 min readOct 10, 2019

It would be surprising if you haven’t heard of a django-allauth as a Django developer. It’s a 3rd party application which makes user registration, sign-up, and social account registration a lot easier. Specifically to my use-case, it also allows users to register and login with just an email and password instead of a username.

But there are times when you when you need extend beyond just a email/password signup e.g. the user must add the name of an “organization” they are joining, a promo code, a referral code etc. It tripped me up a bit at the start so wrote a quick guide.

This short-piece will outline how to;

  • Add additional fields
  • Pull AllAuth forms into your own templates and styling
  • Add additional CSS classes to the forms

Extending (Adding Fields)

The trickiest part of customizing the forms comes to LOCATING the necessary form, but this is a lot easier after I found documentation indicating the forms used for each flow. Choose from the list in the ACCOUNT_FORMS. Now we want to find this form in the repo

My situation did not require adding a significant number of additional fields, so I elected to add these fields dynamically by extending the default allauth signup form (I’d love to hear if there are better practices for this e.g. can we change the meta model the signup form uses, but will this affect validation and such?).

Here I wanted to add a single new field called organization

from allauth.account.forms import SignupFormclass MyCustomSignupForm(SignupForm):    def __init__(self, *args, **kwargs):
super(MyCustomSignupForm, self).__init__(*args, **kwargs)
self.fields['organization'] = forms.CharField(required=True)
def save(self, request):
organization = self.cleaned_data.pop('organization')
...
user = super(MyCustomSignupForm, self).save(request)

And then we need to indicate the new form to use in the settings.py. We’re replacing the form in that dictionary of defaults from the documentation

ACCOUNT_FORMS = {'signup': 'users.forms.MyCustomSignupForm'}

Result (Note: I actually added two fields but just indicating the code for one in this example);

Signup form with additional fields

If we had to add a log statement in the __init__ of the new form and visit the sign-up page, we’d see the new form is in use.

Change Template of Django-AllAuth Forms

Ideally, we want the AllAuth forms to be inheriting from our bases, using our project’s styling etc, so generally the easiest approach is going to be overriding the template.

Finding the templates is not indicated as clearly in the documentation, but all default account registration and signup templates are located in templates. Pick the one which appears correct e.g. check the wording of the template vs. what we see on screen etc. Make a call. We need to;

  • Create an account template directory
  • Find the template we want to extend/override
  • Copy-paste the template code
  • Save the file with the same name
Example of templates I have overridden

Save yourself hours today on Django projects with my free guide, “Top Time-Wasting Beginner Django Mistakes” while still available

In my situation, and for the given templates I overrode, I just had to change the base template inherited and remove anything non-related to the direct form, and use the crispy tag in the form. Note, I also removed lines in the template related to social accounts and a bit of extra I did not require, this is important to be aware of it if you intend to use these features.

Adding CSS

Now if we still need to add specific classes to form fields, or trying to make them fit into a given CSS framework’s requirements, adding custom CSS classes can be achieved in the form’s __init__ as well. This is achieved by interacting with the widgets (this type of interaction is done quite a lot in the source code of AllAuth)

Update all fields;

class MyCustomSignupForm(SignupForm):

def __init__(self, *args, **kwargs):
super(MyCustomSignupForm, self).__init__(*args, **kwargs)
for fieldname, field in self.fields.items():
field.widget.attrs.update({
'class': 'red-border'
})

Update a single field;

class MyCustomSignupForm(SignupForm):

def __init__(self, *args, **kwargs):
super(MyCustomSignupForm, self).__init__(*args, **kwargs)
self.fields['email'].widget.attrs.update({
'class': 'red-border'
})

Summary

Once picking up the spots to dig into django-allauth (and Django forms in general), a lot can be achieved in just a handful of lines, like in the previous examples, but some require a bit more work;

  • Adding fields can be achieved by overriding the default form’s __init__,
  • Adding CSS classes to all the fields requires overriding the form as well (unless you want to do this in the template rather)
  • Completely integrating a template into your project’s templates requires finding the template in the AllAuth repo and copying it over

Sign-up here to receive automation tips, case studies, and guides on the mistakes you maybe making on your automation journey.

And follow me on Twitter where I post about my journey, automation, and business growth.

--

--

Gavin Wiener

I'm a coder and freelancer from South Africa with 5+ years experience in automations, integrations and API's using Python and Django.