请不要浪费你的时间阅读这个问题......这是错误的做法!
查看我自己的答案,了解正确解决方案的分步指南(及解释)
如何使用django-allauth为私人和公司用户注册?
我有以下models
:
class PrivateUser(models.Model):
"""Models a private user account"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
class CompanyUser(models.Model):
"""Models the company's contact person user account"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
class Company(models.Model):
"""Models the company attributes"""
contact_person = models.OneToOneField(User, related_name='company')
name = models.CharField(max_length=50, null=False, blank=False)
vat_no = models.CharField(
# some config and validators
)
# ... other non-relevant fields
现在,我必须在注册过程中区分两个用户PrivateUser
和CompanyUser
,django-allauth只有official django-allauth documentation中指定的一个注册表单:< / p>
ACCOUNT_SIGNUP_FORM_CLASS(=无)
指向自定义表单类的字符串(例如
myapp.forms.SignupForm
) 在注册期间用于询问用户是否有其他输入 (例如通讯报名,出生日期)。这个类应该实现一个def signup(self, request, user)
方法,用户表示 新注册的用户。
因此,为了创建一个独特的表单,我创建了一个包含所有的抽象模型类
PrivateUser
和CompanyUser
加一个字段(请注意user_type
字段):
class AbstractComprehensiveUser(models.Model):
"""
Little hackish model class needed to handle one single sign up
form for multiple users
"""
USER_TYPE_CHOICES = (
('private', 'Private'),
('company', 'Company'),
)
user_type = models.CharField(
max_length=10,
blank=False,
choices=USER_TYPE_CHOICES
)
# Common fields for either private and company users
first_name = models.CharField(max_length=30, blank=False)
last_name = models.CharField(max_length=30, blank=False)
# Company specific fields
company_name = models.CharField(max_length=50, null=True, blank=True)
company_vat_no = models.CharField(
# some config and validators
null=True,
blank = True
)
# other non-relevant fields
class Meta:
abstract = True
N.B:此类中的所有非公共字段都包含属性null=True
和blank=True
。
然后我创建了自定义SignupForm
,如下所示:
class SignupForm(forms.ModelForm):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
class Meta:
model = AbstractComprehensiveUser
fields = (
# Field to differentiate from private and company
# user sign up
'user_type',
# Common fields for either private and company users
'first_name', 'last_name',
# Company specifc fields
'company_name', 'company_vat_no', # etc etc
)
现在的想法是使用两种形式的模板:
user_type='private'
且隐藏first_name
和last_name
字段的user_type='company'
的内容和Company
模型然后,在SignupForm
我将收到user_type
字段,我可以设置正确的表单,例如:
class PrivateUserSignupForm(forms.ModelForm):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
class Meta:
model = PrivateUser
fields = ('first_name', 'last_name')
问题在于,当我在SignupForm.signup()
方法中检索数据时,User
模型已经写入数据库。
我想不保存它,但只是:
signup
方式接收数据以填充正确的表单(PrivateUserSignupForm
或CompanyUserSignupForm
)答案 0 :(得分:5)
我上面写的所有杂乱的东西都是垃圾!
在settings.py
删除ACCOUNT_SIGNUP_FORM_CLASS
时,我们不会使用它。
假设有以下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)
现在,我们想要的是让我们的应用以不同的形式注册PrivateUser
和CompanyUser
。
为了实现这一点,我们将扩展django-allauth的SignupForm
和SignupView
。
在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
现在,我们有CompanyUser
模型和CompanySignupForm
表单。我们使用以下代码在CompanyUserSignupView
中创建views.py
视图:
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()
最后一步,urls.py
:
urlpatterns = [
# ...
url(
r'^accounts/signup/company/$',
views.company_signup,
name='signup-company'
),
]
现在,只需使用您的浏览器转到http://localhost:8000/accounts/signup/company(或根据您的配置使用正确的网址格式)。
您将找到额外的字段,您可以注册公司用户。
现在重复上述所有步骤,以创建PrivateSignupForm
表单,PrivateUserSignupView
视图,并添加正确的网址格式,让用户注册为私有。
上次警告
除非你覆盖,否则django-allauth默认注册网址仍然有效 它与你的一个网址...你应该这样做!
答案 1 :(得分:5)
我遇到了同样的问题。我需要将allauth用于不同的用户配置文件类型。我扩展了allauth SignupView并将其用作我的案例我有一个MemberProfile和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,
)
我想为每种类型的个人资料提供单独的注册页面。幸运的是,allauth SignupView将用户存储在form_value()方法中的实例上。我将SignupView扩展为ProfileView,它需要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
然后我的观点如下:
#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