通过电子邮件或手机号码在Django注册用户

时间:2018-10-11 10:57:05

标签: django django-models django-forms django-views

我有自定义用户模型,其中电子邮件作为auth而不是用户名的唯一标识符。我想通过电子邮件或手机号码注册用户。如果用户输入电子邮件地址,则通过激活链接注册用户;如果用户输入电话号码,则通过SMS OTP注册。

类似于instagram注册:

https://www.instagram.com/accounts/emailsignup/

我找到了this主题,但是答案解释得不好。

1 个答案:

答案 0 :(得分:4)

用户对象必须为username。但是,您也可以将username设置为email,所以(至少在django 2.x中,不确定1.x)是没有问题的。。您没有描述您正在制作的应用程序的用途,用途等, ,因此在跳到代码之前,请阅读以下警告和有关我为何能为您提供更好服务的思考过程选项。

强行要求用户使用与电子邮件相同的用户名是一个非常糟糕的主意,,因为将来您可能需要添加其他功能。

例如::也许您想制作一个留言板,以便人们可以互相交谈。但是由于从一开始就计划不周,每个人都会通过电子邮件看到对方。从技术上讲,您可以为他们分配一堆他们没有组成的随机用户名,但这不是一个好主意,因为他们不太可能记住它,并且他们可能不喜欢它。像sPaRkLe_DaNcEr12Poothtaste这样的名字的唯一好用法是使人们在视频游戏中大发雷霆。

因此,如果您希望将来有能力让用户互相交流,最好只向其他用户显示他们的用户名,但允许用户使用他们的电子邮件或电话号码登录他们想要的。 。现在,他们可以使用自己的(username) or (email) or (phone_number)登录,他们只需要记住其中一个即可。我会告诉你多久。

此方法的一些缺点:它对数据库进行更多查询,如果有大量用户,这可能会使速度变慢,但这就是您的要求。我个人说这是值得的,因为它可以忽略不计,并且对于用户来说更容易,而且您应该迎合它们。因此,为更快的服务器付费,还是没有???最终,您总是应该围绕尽可能少的查询进行设计,同时缓存数据库中很繁重的某些页面,因此不必执行相同的操作X次。

开始吧:

请记住,以下是我将对django 2.x做的一个示例,它的功能比您要求的要好。如果您使用的是1.x,则只需使用url()而不是path()和其他要求。

假设我们有一个名为accounts_app的应用。

还假设我们将path('accounts/', include('accounts_app.urls')),放在项目级别urls.py内。

我还将假设您知道如何使用模板...现在,在该应用中创建一个urls.py

accounts_app / urls.py:

app_name = 'accounts_app'

urlpatterns = [
    ...
    path('signup/', views.signup, name='signup'),
]

accounts_app / models.py:

下面的user属性使您可以扩展User模型,因此也可以使用它们的phone_number。在此示例中,我允许将其保留为空白,以防万一他们不想给它。但是,如果他们这样做了, 您将对此有一个单独的看法。 为了使整个过程变得更加简单,我将不再赘述,也不会告诉您如何覆盖整个用户模型。我仅向您展示如何使用常规User模式的电子邮件登录。在那之后,使用电话号码这样做根本不难。这篇文章的结尾提醒您需要什么。

class ExtendedUserExample(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    phone_number = models.IntegerField(blank=True)

settings.py ....注意,它位于项目级别文件夹中

这些后端的顺序很重要。请始终先执行ModelBackend,否则它将损坏。

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'accounts_app.authentication.EmailAuthBackend',  # to be able to login with email, described next
]

accounts_app / authentication.py:

这是一个能够通过他们的电子邮件登录的示例。如果您也希望某人也通过其电话号码登录,则原理是相同的,但是在此文件中,您还需要导入上面的ExtendedUserExample模型,并将其添加到上述的设置AUTHENTICATION_BACKENDS中在其底部,并为PhoneAuthBackend创建一个新类,在ExtendedUserExample中搜索phone_number。再次,为了简化操作,我不会完全覆盖User模型,而只是扩展它,因此,如果用户注册了一个帐户并希望以后通过电话号码登录,则他们必须注册首先输入用户名和电子邮件,然后输入一个电话号码(在此示例中,您将需要另一个视图)。

因此,请首先尝试使用此电子邮件示例,直到掌握了它为止。您也不需要将文件导入其他任何地方,因为settings.py文件会处理该文件。

正在发生的事情::在您用于登录的模板上,它将首先在username模型内搜索User字段,因为您的settings.py文件拥有AUTHENTICATION_BACKENDS变量来首先检查ModelBackend

但是,假设用户输入了username作为aaa@aaa.com。现在,由于您不允许任何人使用电子邮件作为用户名进行注册,因此在aaa@aaa.com模型中找不到username作为User的情况下,您的设置文件现在说可以再次检查相同的User对象,但通过email字段/列搜索其输入。如果该列中存在他们的输入,则authenticate()将在密码正确的情况下通过他们的电子邮件登录。

from django.contrib.auth.models import User

class EmailAuthBackend(object):
    """ Authenticate using an email address """

    def authenticate(self, request, username=None, password=None):
        try:
            user = User.objects.get(email=username)  # gets the email by the 'username' they entered
            if user.check_password(password):
                return user
            return None
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

acounts_app / views.py:

我假设您知道如何制作Django表格。如果没有,check here for model forms.

from .forms import ExtendedUserForm

def signup(request):
    form = ExtendedUserForm(request.POST or None)
    if request.method == 'POST':
        if request.POST['password1'] == request.POST['password2']:
            potential_user = request.POST.get('username', False).lower()
            try:
                user = User.objects.get(username=potential_user)
                return render(request, 'accounts_app/signup.html', {'error': 'Username has already been taken. Please try another'})
            except User.DoesNotExist:
                if form.is_valid():
                    new_user = User.objects.create_user(username=potential_user, email=request.POST['email'], password=request.POST['password1'])

                    # backend argument required cause we are making the ability to LOGIN by email.
                    # Remember, I only extended the User model.
                    auth.login(request, new_user, backend='django.contrib.auth.backends.ModelBackend')

                    return redirect('some_app:some_view')
        else:
            return render(request, 'accounts_app/signup.html', {'error': "Password's must match."})
    return render(request, 'accounts_app/signup.html', {'form': form})

现在您应该可以通过电子邮件登录了,遵循这些原则创建相同的电话登录功能并不难。如果继续执行本示例,则需要创建新视图以将电话号码保存到ExtendedUserExample.phone_number。之后,在AUTHENTICATION_BACKENDS的底部添加另一行,在authentication.py中编写一个新的类,只要您使用<input type="text" name="username" required>,当他们使用{登录视图。