I work with Django-Allauth and React as a FE. I added a parameter called name for for the Custom User I created, I've overridden the SignupForm in Forms.py to save it, and just like the documentation said I changed the settings.py to have
ACCOUNT_FORMS = {'signup': 'XXXX.forms.CustomSignupForm'}
But the form does not get initiated when signing up - i added prints that don't go through. A user is being created - but probably with the default form, and doesn't add the additional parameter I added. I checked and the frontend sends the payload properly.
I have this in forms.py
class CustomUserCreationForm(UserCreationForm):
name = forms.CharField(max_length=30, required=True, help_text='Enter your name.')
class Meta:
model = CustomUser
fields = ("email", "name")
class CustomSignupForm(SignupForm):
name = forms.CharField(max_length=40, required=True, help_text='Enter your name.')
def __init__(self, *args, **kwargs):
print("CustomSignupForm is being initialized")
super().__init__(*args, **kwargs)
def save(self, request):
print("im working")
user = super().save(request)
user.name = self.cleaned_data['name']
user.save()
return user
urls.py
urlpatterns = [
path("admin/", admin.site.urls),
path('', include('XXXX.urls')),
path('accounts/', include('allauth.urls')),
path("_allauth/", include("allauth.headless.urls")),
]
I also tried using an ACCOUNT_ADAPTER in settings, and this is how the adapter looks in adapters.py
class CustomAccountAdapter(DefaultAccountAdapter):
# def get_signup_form_class(self):
# return CustomSignupForm
But it didn't use the form.
Also tried to edit the CustomUserManager, but the form is a step before it if I'm not mistaken so it didn't help as well. I tried looking everywhere, and in the documentation, but couldn't find a solution or a hint. Thanks a lot!
Edit- adding settings.py
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = "XXX"
DEBUG = True
ALLOWED_HOSTS = ['127.0.0.1','localhost']
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000"
]
CSRF_TRUSTED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000"
]
CORS_ALLOW_CREDENTIALS = True
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"myapp",
'rest_framework',
'corsheaders',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.facebook',
'allauth.socialaccount.providers.google',
]
SITE_ID = 1
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"allauth.account.middleware.AccountMiddleware",
]
ROOT_URLCONF = "project.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
'django.template.context_processors.request',
],
},
},
]
WSGI_APPLICATION = "project.wsgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
AUTH_USER_MODEL = "myapp.CustomUser"
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",},
]
AUTHENTICATION_BACKENDS = [
# Needed to login by username in Django admin, regardless of `allauth`
'django.contrib.auth.backends.ModelBackend',
# `allauth` specific authentication methods, such as login by email
'allauth.account.auth_backends.AuthenticationBackend',
]
SOCIALACCOUNT_PROVIDERS = {
'google': {
'APP': {
'client_id': '123',
'secret': '456',
'key': ''
}
}
}
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
STATIC_URL = "static/"
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
ACCOUNT_EMAIL_VERIFICATION = "optional" # or "optional"
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = False
ACCOUNT_LOGIN_BY_CODE_ENABLED = True
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_FORMS = {'signup': 'app.forms.CustomSignupForm'}
HEADLESS_FRONTEND_URLS = {
"account_confirm_email": "https://app.project.org/account/verify-email/{key}",
"account_reset_password": "https://app.project.org/account/password/reset",
"account_reset_password_from_key": "https://app.project.org/account/password/reset/key/{key}",
"account_signup": "https://app.project.org/account/signup",
"socialaccount_login_error": "https://app.project.org/account/provider/callback",
}
An important thing to keep in mind is that there is no one-to-one
mapping of headed forms to headless input payloads. For example, while having to
enter your password twice makes sense in a headed environment, it is pointless
from an API point of view. As a result, the headed forms that can be overridden
by means of ACCOUNT_FORMS
play no role in the headless environment.
Instead of overriding the complete signup form via ACCOUNT_FORMS
, provide a
ACCOUNT_SIGNUP_FORM_CLASS
that derives from forms.Form
and only lists
the additional fields you need. These fields will automatically show up in the
headed signup form, and will automatically be validated when posting payloads to
the signup endpoint.