19👍
TL;DR
All the messy stuff I wrote above are junk!
The (final) right solution
In settings.py
remove ACCOUNT_SIGNUP_FORM_CLASS
, we won’t use it.
Suppose to have the following models
:
class PrivateUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
class CompanyUser(models.Model):
contact_person = models.OneToOneField(User, on_delete=models.CASCADE)
company_name = models.CharField(max_length=50, null=False, blank=False)
Now, what we want is to let our app signup the PrivateUser
and the CompanyUser
with different forms.
To accomplish that we’ll extends the django-allauth’s SignupForm
and SignupView
.
In forms.py
:
from myapp.models import CompanyUser
class CompanySignupForm(SignupForm):
# declare here all the extra fields in CompanyUser model WITHOUT
# the OneToOneField to User
# (N.B: do NOT try to declare Meta class with model=CompanyUser,
# it won't work!)
company_name = forms.CharField(max_length=50, required=True, strip=True)
# Override the save method to save the extra fields
# (otherwise the form will save the User instance only)
def save(self, request):
# Save the User instance and get a reference to it
user = super(CompanySignupForm, self).save(request)
# Create an instance of your model with the extra fields
# then save it.
# (N.B: the are already cleaned, but if you want to do some
# extra cleaning just override the clean method as usual)
company_user = CompanyUser(
contact_person=user,
company_name=self.cleaned_data.get('company_name')
)
company_user.save()
# Remember to return the User instance (not your custom user,
# the Django one), otherwise you will get an error when the
# complete_signup method will try to look at it.
return company_user.contact_person
Now, we have CompanyUser
model and CompanySignupForm
form. Let’s create a CompanyUserSignupView
view in views.py
with the following code:
class CompanyUserSignupView(SignupView):
# The referenced HTML content can be copied from the signup.html
# in the django-allauth template folder
template_name = 'account/signup_company.html'
# the previously created form class
form_class = CompanySignupForm
# the view is created just a few lines below
# N.B: use the same name or it will blow up
view_name = 'company_signup'
# I don't use them, but you could override them
# (N.B: the following values are the default)
# success_url = None
# redirect_field_name = 'next'
# Create the view (we will reference to it in the url patterns)
company_signup = CompanyUserRegistrationView.as_view()
Last step, the urls.py
:
urlpatterns = [
# ...
url(
r'^accounts/signup/company/$',
views.company_signup,
name='signup-company'
),
]
Now, just use your browser to go to http://localhost:8000/accounts/signup/company (or the proper url pattern based on your configuration).
You will find the extra fields and you can signup a company user.
Now repeat all the previous steps to create a PrivateSignupForm
form, a PrivateUserSignupView
view and add the proper url pattern to let users signup as privates.
LAST WARNING
The django-allauth default signup url will still works unless you override
it with one of your url… and you should do that!
11👍
I had the same problem. I needed to use allauth for different user profile types. I extended the allauth SignupView and used it as a In my case I have a MemberProfile and PartnerProfile:
#profile models
class MemberProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
class PartnerProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
I want a separate signup page for each type of profile. Luckily the allauth SignupView stores the user on it’s instance in the form_value() method. I extend the SignupView as ProfileView which expects a profile_class :
#mixin
from allauth.account.views import SignupView
from allauth.account.forms import SignupForm
class ProfileSignupView(SignupView):
template_name = 'profiles/register.html'
success_url = '' # profile specific success url
form_class = SignupForm
profile_class = None # profile class goes here
def form_valid(self, form):
response = super(ProfileSignupView, self).form_valid(form)
profile = self.profile_class(user=self.user)
profile.save()
return response
then my views look like this:
#views
from .mixins import ProfileSignupView
from .models import PartnerProfile, MemberProfile
class MemberSignupView(ProfileSignupView):
success_url = '/member/profile'
profile_class = MemberProfile
class PartnerSignupView(ProfileSignupView):
success_url = '/partner/profile'
profile_class = PartnerProfile