多用户类型使用 django-allauth 注册

问题描述 投票:0回答:3

编辑

请不要浪费时间阅读问题...这是错误的方法!

查看我自己的答案,获取正确解决方案的分步指南(带解释)

TL;博士

如何使用 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 只有一张注册表单,如 官方 django-allauth 文档中指定的那样:

ACCOUNT_SIGNUP_FORM_CLASS(=无)

指向自定义表单类的字符串(例如

myapp.forms.SignupForm

)
     在注册过程中用于要求用户提供额外的输入
     (例如时事通讯注册、出生日期)。这个类应该实现一个
     
def signup(self, request, user)
 方法,其中 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

注意:此类中所有非公共字段都具有属性 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
  • 验证表格
    • 如果没有错误,请保存用户和其他模型
    • 如果出现错误,请勿保存任何内容并警告用户有关错误的信息
问题是...

    这种做法正确吗?还有其他方法可以在不进行这些复杂操作的情况下完成此任务吗?
  • 如果这种方法是正确的,我该如何处理上面描述的工作流程?
django django-forms django-allauth
3个回答
19
投票
TL;博士

我上面写的那些乱七八糟的东西都是垃圾!

(最终)正确的解决方案

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(或根据您的配置使用正确的 URL 模式)。

您将找到额外的字段,您可以注册公司用户。

现在重复前面的所有步骤来创建一个

PrivateSignupForm

 表单、一个 
PrivateUserSignupView
 视图并添加正确的 url 模式以让用户以私人身份注册。

最后警告

django-allauth 默认注册 url 仍然有效,除非您覆盖 它与您的网址之一...您应该这样做!


11
投票
我也有同样的问题。我需要对不同的用户配置文件类型使用 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
    

0
投票
使用 allauth 来探索对我有用的选项:

模型.py

class AccountTypeOne(User): class Meta: proxy = True class AccountTypeTwo(User): class Meta: proxy = True
表格.py

class AccountSignupForm(SignupForm): USER_CHOICES = ( ("type_one", "TypeOne"), ("type_two", "TypeTwo"), ) account_type = forms.ChoiceField(choices=USER_CHOICES, widget=forms.Select) def save(self, request): account_type = self.cleaned_data.get("account_type") if account_type == "type_one": user = AccountTypeOne() elif account_type == "type_two": user = AccountTypeTwo() else: raise ValueError("Invalid user type") user.username = self.cleaned_data.get("username") user.email = self.cleaned_data.get("email") user.set_password(self.cleaned_data.get("password1")) user.save() return user
希望有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.