django-allauth
django-allauth copied to clipboard
CustomSignupForm method signup() doesn't get called
Thank you for django-allauth :-)
I tried creating a custom signup form like this
class CustomSignupForm(SignupForm):
first_name = forms.CharField(max_length=30, label="First Name")
last_name = forms.CharField(max_length=150, label="Last Name")
company = forms.CharField(max_length=50, label="Company Name")
def signup(self, request, user):
print("hello "*10)
user.first_name = self.cleaned_data["first_name"]
user.last_name = self.cleaned_data["last_name"]
user.profile.company = self.cleaned_data['company']
user.save()
and I linked it in settings.py
with
ACCOUNT_FORMS = {"signup": "users.forms.CustomSignupForm"}
I noticed that the form contains the additional fields but the signup()
method doesn't get called. There ist no debug output and the company
is not saved. first_name
and last_name
are saved, giving the impression that signup()
is called when in fact they are saved by the adapter of the model. Took me a while to figure that out :-/.
Having dug a bit deeper, I think the problem is due to the custom_signup()
method of the BaseSignupForm()
class especially this line
https://github.com/pennersr/django-allauth/blob/ef0774318993c2f7757df6ca2b962bc0df1d5674/allauth/account/forms.py#L350
Since custom_signup()
is a method of BaseSignupForm()
and not SignupForm()
or even CustomSignupForm()
the super()
call always finds the signup()
method of _DummyCustomSignupForm()
, which is empty.
Overwriting custom_signup()
in CustomSignupForm()
fixes the problem.
class CustomSignupForm(SignupForm):
first_name = forms.CharField(max_length=30, label=_("First Name"))
last_name = forms.CharField(max_length=150, label=_("Last Name"))
company = forms.CharField(max_length=50, label=_("Company Name"))
def custom_signup(self, request, user):
custom_form = self #use local signup()
if hasattr(custom_form, 'signup') and callable(custom_form.signup):
custom_form.signup(request, user)
def signup(self, request, user):
user.first_name = self.cleaned_data["first_name"]
user.last_name = self.cleaned_data["last_name"]
user.profile.company = self.cleaned_data['company']
user.save()
My question: Is this even the correct approach? StackOverflow tells me I should inherit from forms.Form
and have a signup()
method. The documentation tells me I should subclass SignupForm
but have a safe()
method. custom_signup()
says save()
is deprecated.
Im using Django 3, Python 3.7 and django-allauth 0.41.0
Probably unrelated problem, but substituting ACCOUNT_FORMS = {"signup": "users.forms.CustomSignupForm"}
with ACCOUNT_SIGNUP_FORM_CLASS = "users.forms.CustomSignupForm"
also does not work.
I tried it in the shell, and the form has the signup method.
~/django_frontend (master *%)$ ./manage.py shell -i ipython
Python 3.7.6 (default, Dec 30 2019, 19:38:26)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.11.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from importlib import import_module
In [2]: mod = import_module("users.forms")
In [3]: getattr(mod, "CustomSignupForm")
Out[3]: users.forms.CustomSignupForm
In [4]: fc_class = getattr(mod, "CustomSignupForm")
In [5]: hasattr(fc_class, 'signup')
Out[5]: True
When I set ACCOUNT_SIGNUP_FORM_CLASS
, I get
~/django_frontend (master *%)$ ./manage.py shell -i ipython
Traceback (most recent call last):
File "/Users/dev/.local/share/virtualenvs/django_frontend-uhtkvvFX/lib/python3.7/site-packages/allauth/account/forms.py", line 243, in _base_signup_form_class
fc_class = getattr(mod, fc_classname)
AttributeError: module 'users.forms' has no attribute 'CustomSignupForm'
...
django.core.exceptions.ImproperlyConfigured: Module "users.forms" does not define a "CustomSignupForm" class
I'm also seeing this. The docs say
ACCOUNT_SIGNUP_FORM_CLASS (=None)
A string pointing to a custom form class (e.g. ‘myapp.forms.SignupForm’) that is used during signup to ask the user for additional input (e.g. newsletter signup, birth date). This class should implement a def signup(self, request, user) method, where user represents the newly signed up user.
but other parts of the docs suggest using save
not signup
. So at least this reference to signup
should be removed to save some headaches.
A slightly simpler solution is to directly override custom_signup
with your custom code. @omni-vi 's code modified to show this:
class CustomSignupForm(SignupForm):
first_name = forms.CharField(max_length=30, label=_("First Name"))
last_name = forms.CharField(max_length=150, label=_("Last Name"))
company = forms.CharField(max_length=50, label=_("Company Name"))
def custom_signup(self, request, user):
user.first_name = self.cleaned_data["first_name"]
user.last_name = self.cleaned_data["last_name"]
user.profile.company = self.cleaned_data['company']
user.save()
@pennersr Close as discussion
Users who want custom signup forms should simply inherit Signup Form
from allauth.account.forms import SignupForm
class CustomSignupForm(SignupForm):
def save(self, request):
# Ensure you call the parent class's save.
# .save() returns a User object.
user = super(CustomSignupForm, self).save(request)
# Add your own processing here.
# You must return the original result.
return user
You can read more in the docs. You may or may not need to add an account adapter as well.