Django - 创建两种用户类型,其中一种类型可以是两种类型
Django - Creating two user types, where one type can be both
我们需要为两种不同类型的用户提供两种不同的表单。称他们为 Client
和 Provider
。 Client 将是父级、基本用户,而 Provider 是一种扩展。在任何时候,客户也可以成为提供者,同时仍保持作为客户的状态和信息。因此,提供者具有作为客户和提供者的两种权限。
我是 Django 的新手。我们要做的就是注册任一用户类型,但如果用户立即注册为提供者,则在提供者和客户端 table 之间具有一对一的关系。
我们遇到的问题是在适配器中,我们认为。提供商注册正常,但最终出现在 users_user
table 中,在生成的 users_provider
table 中没有任何条目。这是我们试图在数据库中保存和关联这两个实体的方式,还是其他方式?
我们正在尝试使用 allauth 进行身份验证和注册。
我们的代码:
models.py:
class User(AbstractUser):
name = models.CharField(_('Name of User'), blank=True, max_length=255)
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('users:detail', kwargs={'username': self.username})
SEX = (
("M","MALE"),
("F","FEMALE"),
)
birthdate = models.DateField(_('Birth Date'), default=django.utils.timezone.now, blank=False)
sex = models.CharField(_('Sex'), choices=SEX, max_length=1, default="M")
isProvider = models.BooleanField(_('Provider'), default=False)
#Using User, not models.Model
class Provider(User):
HAS_BUSINESS = (
('YES','YES'),
('NO','NO'),
)
#Resolving asociation 1:1 to User
#NOTE: AUTH_USER_MODEL = users.User in setting
owner = models.OneToOneField(settings.AUTH_USER_MODEL)
has_business = models.CharField(_('Do you have your own business?'),max_length=2, choices=HAS_BUSINESS, default='NO')
isProvider = True
我们的forms.py
class ProviderForm(SignupForm,ModelForm):
name = forms.CharField(label='Name', strip=True, max_length=50)
lastname = forms.CharField(label='Last Name', strip=True, max_length=50)
Provider.isProvider = True
class Meta:
model = Provider
fields = '__all__'
exclude = GENERAL_EXCLUSIONS + [
'owner',
]
class ClientForm(SignupForm,ModelForm):
name = forms.CharField(label='Name', strip=True, max_length=50)
lastname = forms.CharField(label='Last Name', strip=True, max_length=50)
class Meta:
model = User
fields = "__all__"
exclude = GENERAL_EXCLUSIONS
def is_active(self):
return False
def __init__(self, *args, **kwargs):
super(ClientForm, self).__init__(*args, **kwargs)
views.py:
class ProviderRegisterView(SignupView):
template_name = 'account/form_provider.html'
form_class = ProviderForm
redirect_field_name = 'next'
view_name = 'registerprovider'
success_url = None
def get_context_data(self, **kwargs):
ret = super(ProviderRegisterView, self).get_context_data(**kwargs)
ret.update(self.kwargs)
return ret
registerprovider = ProviderRegisterView.as_view()
#View para el formulario de registro de usuarios clientes
class ClientRegisterView(SignupView):
template_name = 'account/form_client.html'
form_class = ClientForm
redirect_field_name = 'next'
view_name = 'registerclient'
success_url = None
def get_context_data(self, **kwargs):
ret = super(ClienteRegisterView, self).get_context_data(**kwargs)
ret.update(self.kwargs)
return ret
registerclient = ClienteRegisterView.as_view()
最后,我们的 adapter.py:
#Per allauth documentation, settings changed:
#ACCOUNT_ADAPTER = 'projectname.users.adapters.RegisterUserAdapter'
class RegisterUserAdapter(DefaultAccountAdapter):
def save_user(self, request, user, form, commit=True):
data = form.cleaned_data
user.first_name = data['name']
user.last_name = data['lastname']
#Saving Client info
user.sex = data['sex']
user.birthdate = data['birthdate']
#Normal allauth saves
user.username = data['username']
user.email = data['email']
if user.isProvider:
p = Provider()
p.owner = user
p.has_business = data['has_business']
if 'password1' in data:
user.set_password(data['password1'])
else:
user.set_unusable_password()
self.populate_username(request, user)
if commit:
#Save user
user.save()
#If it's also a Provider, save the Provider
if user.isProvider:
p.save()
return user
如有任何帮助或提示,我们将不胜感激。如果我遗漏了什么,请告诉我。我不确定问题出在模型本身、我们表示表单的方式还是适配器。就目前而言,无论我们使用什么形式,它总是保存为基本用户 table(我们的客户端),而提供者 table 永远不会将信息保存到它。
使用Django新的自定义用户模型,只能设置一个用户模型为settings.AUTH_USER_MODEL
。在您的示例中,您可以将其设置为您的 User
模型。
然后,对于可选的提供程序数据,创建一个单独的模型,供 OneToOneField
从您的 User
模型中引用。
class User(AbstractUser):
...
provider = models.OneToOneField(Provider, null=True)
class Provider(models.Model):
...
考虑到 AUTH_USER_MODEL
约束,这是在 Django 中处理多种用户类型的最简单方法。
此外,最好只对抽象模型进行子类化,否则您会得到多表继承,这会导致隐藏的隐含 JOIN,从而降低性能。
最后,您可以在自定义表单的 form.is_valid()
方法中创建 Provider
对象并分配 user.provider = provider
.
我们需要为两种不同类型的用户提供两种不同的表单。称他们为 Client
和 Provider
。 Client 将是父级、基本用户,而 Provider 是一种扩展。在任何时候,客户也可以成为提供者,同时仍保持作为客户的状态和信息。因此,提供者具有作为客户和提供者的两种权限。
我是 Django 的新手。我们要做的就是注册任一用户类型,但如果用户立即注册为提供者,则在提供者和客户端 table 之间具有一对一的关系。
我们遇到的问题是在适配器中,我们认为。提供商注册正常,但最终出现在 users_user
table 中,在生成的 users_provider
table 中没有任何条目。这是我们试图在数据库中保存和关联这两个实体的方式,还是其他方式?
我们正在尝试使用 allauth 进行身份验证和注册。
我们的代码:
models.py:
class User(AbstractUser):
name = models.CharField(_('Name of User'), blank=True, max_length=255)
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('users:detail', kwargs={'username': self.username})
SEX = (
("M","MALE"),
("F","FEMALE"),
)
birthdate = models.DateField(_('Birth Date'), default=django.utils.timezone.now, blank=False)
sex = models.CharField(_('Sex'), choices=SEX, max_length=1, default="M")
isProvider = models.BooleanField(_('Provider'), default=False)
#Using User, not models.Model
class Provider(User):
HAS_BUSINESS = (
('YES','YES'),
('NO','NO'),
)
#Resolving asociation 1:1 to User
#NOTE: AUTH_USER_MODEL = users.User in setting
owner = models.OneToOneField(settings.AUTH_USER_MODEL)
has_business = models.CharField(_('Do you have your own business?'),max_length=2, choices=HAS_BUSINESS, default='NO')
isProvider = True
我们的forms.py
class ProviderForm(SignupForm,ModelForm):
name = forms.CharField(label='Name', strip=True, max_length=50)
lastname = forms.CharField(label='Last Name', strip=True, max_length=50)
Provider.isProvider = True
class Meta:
model = Provider
fields = '__all__'
exclude = GENERAL_EXCLUSIONS + [
'owner',
]
class ClientForm(SignupForm,ModelForm):
name = forms.CharField(label='Name', strip=True, max_length=50)
lastname = forms.CharField(label='Last Name', strip=True, max_length=50)
class Meta:
model = User
fields = "__all__"
exclude = GENERAL_EXCLUSIONS
def is_active(self):
return False
def __init__(self, *args, **kwargs):
super(ClientForm, self).__init__(*args, **kwargs)
views.py:
class ProviderRegisterView(SignupView):
template_name = 'account/form_provider.html'
form_class = ProviderForm
redirect_field_name = 'next'
view_name = 'registerprovider'
success_url = None
def get_context_data(self, **kwargs):
ret = super(ProviderRegisterView, self).get_context_data(**kwargs)
ret.update(self.kwargs)
return ret
registerprovider = ProviderRegisterView.as_view()
#View para el formulario de registro de usuarios clientes
class ClientRegisterView(SignupView):
template_name = 'account/form_client.html'
form_class = ClientForm
redirect_field_name = 'next'
view_name = 'registerclient'
success_url = None
def get_context_data(self, **kwargs):
ret = super(ClienteRegisterView, self).get_context_data(**kwargs)
ret.update(self.kwargs)
return ret
registerclient = ClienteRegisterView.as_view()
最后,我们的 adapter.py:
#Per allauth documentation, settings changed:
#ACCOUNT_ADAPTER = 'projectname.users.adapters.RegisterUserAdapter'
class RegisterUserAdapter(DefaultAccountAdapter):
def save_user(self, request, user, form, commit=True):
data = form.cleaned_data
user.first_name = data['name']
user.last_name = data['lastname']
#Saving Client info
user.sex = data['sex']
user.birthdate = data['birthdate']
#Normal allauth saves
user.username = data['username']
user.email = data['email']
if user.isProvider:
p = Provider()
p.owner = user
p.has_business = data['has_business']
if 'password1' in data:
user.set_password(data['password1'])
else:
user.set_unusable_password()
self.populate_username(request, user)
if commit:
#Save user
user.save()
#If it's also a Provider, save the Provider
if user.isProvider:
p.save()
return user
如有任何帮助或提示,我们将不胜感激。如果我遗漏了什么,请告诉我。我不确定问题出在模型本身、我们表示表单的方式还是适配器。就目前而言,无论我们使用什么形式,它总是保存为基本用户 table(我们的客户端),而提供者 table 永远不会将信息保存到它。
使用Django新的自定义用户模型,只能设置一个用户模型为settings.AUTH_USER_MODEL
。在您的示例中,您可以将其设置为您的 User
模型。
然后,对于可选的提供程序数据,创建一个单独的模型,供 OneToOneField
从您的 User
模型中引用。
class User(AbstractUser):
...
provider = models.OneToOneField(Provider, null=True)
class Provider(models.Model):
...
考虑到 AUTH_USER_MODEL
约束,这是在 Django 中处理多种用户类型的最简单方法。
此外,最好只对抽象模型进行子类化,否则您会得到多表继承,这会导致隐藏的隐含 JOIN,从而降低性能。
最后,您可以在自定义表单的 form.is_valid()
方法中创建 Provider
对象并分配 user.provider = provider
.