通过扩展用户模型中的电话字段登录
Posted
技术标签:
【中文标题】通过扩展用户模型中的电话字段登录【英文标题】:Login via Phone field in Extended User Model 【发布时间】:2020-01-08 03:07:44 【问题描述】:我使用了 django 用户模型并将其扩展为添加电话字段。我可以使用用户名或电子邮件登录,但无法从扩展用户模型访问电话号码字段。
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phonenumber = models.CharField(max_length=10)
后端.py
class AuthenticationBackend(backends.ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
usermodel = get_user_model()
print(usermodel)
try:
user = usermodel.objects.get(Q(username__iexact=username) | Q(
email__iexact=username))
if user.check_password(password):
return user
except user.DoesNotExist:
pass
backend.py 是我用来通过用户名或电子邮件实现登录的,但我无法在扩展用户模型中对 phonenumber 执行此操作。
【问题讨论】:
您可以显示您尝试通过 phone_number 获取用户时的代码吗? 我没有尝试通过电话号码获取用户。我被困在这里。我不知道如何在扩展用户模型中访问电话号码 你可以试试usermodel.objects.get(Q(profile__phonenumber=some_phone_number))
。从User
到Profile
的关系就是profile
。但是你应该让phonenumber
在你的模型上是唯一的,否则你会有多个用户使用相同的电话号码的风险,例外不会是usermodel.DoesNotExist
,而是usermodel.MultipleObjectsReturned
。
我认为,如果您想使用电话号码作为身份验证字段,那么您最好扩展 AbstractBaseUser 类,而不是像您一样将您的个人资料映射到 User 。请参阅此处了解更多信息:simpleisbetterthancomplex.com/tutorial/2016/07/22/…
但正如@urbanespaceman 所提到的,在这种情况下,最好创建您的自定义User
模型,正如here 所解释的那样。
【参考方案1】:
有两种方法可以解决您的问题。
-
通过继承用户模型并更改默认用户模型来扩展用户模型。我建议您走这条路线,因为电话号码用于身份验证。
在 Profile 上设置 related_name,并根据该名称查询 User 模型。
对于第一个,我建议您查看Django documentation on creating custom users. 还有一个关于如何做到这一点的相当广泛的教程here。
如果你想走简单的路,你只需要在个人资料的电话号码字段上设置一个反向访问器。
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phonenumber = models.CharField(max_length=10, related_name='profile')
然后您可以通过用户个人资料的电话号码搜索用户:
class AuthenticationBackend(backends.ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
usermodel = get_user_model()
print(usermodel)
try:
user = usermodel.objects.get(Q(username__iexact=username) | Q(
email__iexact=username) | Q(profile__phonenumber__iexact=username)
if user.check_password(password):
return user
except user.DoesNotExist:
pass
虽然这不在您的问题范围内,但我认为您应该注意您的代码存在以下问题:
电话号码通常比 10 个字符的字符串更复杂。 +31 6 12345678,是一个有效的电话号码,但超过 10 个字符。查看 this question 获取有关如何存储和验证电话号码的指导。 如果您使用字段进行身份验证,请确保它是唯一的。 phonenumber 字段实际上应该是phonenumber = models.CharField(max_length=10, related_name='profile', unique=True)
如果有电话号码为“0123456789”的用户和用户名“0123456789”的其他用户,您的usermodel.objects.get(...)
查询将返回多个用户。您应该限制用户名不包含电话号码,这只能通过扩展默认的 User 类来实现。
【讨论】:
【参考方案2】:您可以扩展 AbstractUser 并在其上添加电话号码。
class User(AbstractUser):
phonenumber = models.CharField(max_length=10)
USERNAME_FIELD = 'phonenumber'
那么你应该在settings.py中将自定义模型指定为默认用户模型
AUTH_USER_MODEL = 'app_name.User'
Customizing authentication in Django
【讨论】:
以上是关于通过扩展用户模型中的电话字段登录的主要内容,如果未能解决你的问题,请参考以下文章
如何将电话号码字段添加到 django UserCreationForm?