如何用Django注册和登录用户

525 阅读11分钟

Django有一些内置的工具,你可以用来设置用户登录和注销网络应用程序的功能。在本教程中,我们将看到如何设置该功能。首先,我们将设置我们需要的url模式和路由,然后我们将配置所需的视图函数。在视图函数中,我们将利用Django提供的两个非常酷的类。那就是 UserCreationForm 和 AuthenticationForm 类。这两个类提供了一种方法,可以将整个注册和登录表单的配置支架化,以处理这些任务,并在其中建立验证。让我们开始吧。

帐户应用程序

我们首先在Django项目中创建一个名为accounts的新应用,以保存我们需要的登录和注销功能的文件。

djangoblog $python manage.py startapp accounts

django accounts app

用Django注册应用程序

任何时候你想在Django项目中使用一个新的应用程序,你都需要在settings.py文件中注册它。下面我们看到我们的Django项目中有两个自定义的应用程序,一个用于帖子,一个用于账户

djangoblog/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'posts',
    'accounts'
]

添加urls.py

该 **startapp**并不会在它创建的新应用中自动生成urls.py文件。我们在这个应用中需要一个,所以在Pycharm中,我们现在可以添加这个文件。

add urlspy to app

命名空间和URL模式

首先,我们需要一种方法来向应用程序的用户显示一个表单,以提供一个注册的机会。另外,请注意,我们给这个应用程序一个账户的命名空间。这样在使用命名的路由时,如果在不同的应用程序中有相同名称的路由,Django就不会感到困惑。它可以使用命名空间来确定哪个是哪个。

accounts/urls.py

from django.urls import path
from . import views

app_name = 'accounts'

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

上面的代码简单地定义了一个模式,即如果用户在/accounts命名空间中访问/signup,就会触发**signup_view()**函数。我们将在稍后看到该函数的作用。

包括URLS

在我们的Django教程中,我们已经见过几次这种模式了,那就是在Django项目的基础urls.py文件中,包括一个应用程序的URL模式。下面突出显示的代码确保用户在任何时候[访问http://example.com/accounts,他们将使用account/urls.py中定义的url模式(如上图所示)。

djangoblog/urls.py

from django.contrib import admin
from django.urls import path, include
from . import views

urlpatterns = [
    path('', views.home),
    path('admin/', admin.site.urls),
    path('accounts/', include('accounts.urls')),
    path('posts/', include('posts.urls')),
    path('about/', views.about)
]

定义视图函数

现在我们可以定义一些视图函数来处理Http请求。首先,我们定义一个signup_view(),它接受Http请求,然后返回signup.html模板的渲染,我们将在稍后创建。

accounts/views.py

from django.shortcuts import render


# Create your views here.
def signup_view(request):
    return render(request, 'accounts/signup.html')

在Pycharm中,我们可以选择添加一个新的目录,并提供templates/accounts的路径,这为我们的模板提供了一个很好的命名空间,即accounts/templates/accounts。

django namespaced templates

然后在我们的新目录中,我们添加signup.html模板。

pycharm new html file

我们还将定义一个布局文件夹,以容纳一个我们可以扩展的base.html模板。

base template django

在布局目录中,我们像这样创建base.html文件。

extend base html django

base.html模板的内容在这里显示。这与我们在Django的静态文件和图片教程中学习的设置相同。

accounts/templates/accounts/layout/base.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    {% load static %}
    <link rel="stylesheet" href="{% static "posts/css/bootstrap.min.css" %}">

    <title>Django Blog</title>
</head>
<body class="container mt-5">
{% block content %}

{% endblock content %}
</body>
</html>

signup.html模板是由这个基础布局延伸出来的,现在我们只需添加一个简单的H1标签,让我们知道这是一个注册页面。

accounts/templates/accounts/signup.html

{% extends "./layout/base.html" %}
{% load static %}

{% block content %}
    <h1>Signup</h1>
{% endblock content %}

好吧,这只是几个步骤,但现在我们应该有一个访问http://localhost:8000/accounts/signup/ 的工作场景。首先确保Django服务器正在运行,在终端输入python manage.py runserver,然后访问该网站。看起来不错!

django user sign up page


Django UserCreationForm

现在我们可以看到Django的一些非常酷的魔法了。**UserCreationForm()**就是这样一个神奇的东西。这个类就是所谓的模型表单。它之所以这么酷,是因为它能一次性为你完成一系列的步骤,包括为表单生成Html标记以显示在模板中。

一个用于创建一个新用户的ModelForm。

它有三个字段:用户名(来自用户模型),密码1,和密码2。它验证password1和password2是否匹配,使用validate_password()验证密码,并使用set_password()设置用户的密码。

为了使用这个模型表单,我们首先在文件的顶部导入它。在第7行,使用*form = UserCreationForm()*创建这个模型表单的一个新实例。在第8行的render()函数中,我们可以使用字典作为第三个参数把这个表单传递给模板。

accounts/views.py

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm


# Create your views here.
def signup_view(request):
    form = UserCreationForm()
    return render(request, 'accounts/signup.html', {'form': form})

现在在signup.html模板中,我们只需手动添加开头和结尾的

标签。在开头和结尾的标签之间,你所要做的就是使用{{ form }}来输出一个非常漂亮的用户注册表。

accounts/templates/accounts/signup.html

{% extends "./layout/base.html" %}
{% load static %}

{% block content %}
    <h1>Signup</h1>
    <form action="/accounts/signup/" method="post">
        {{ form }}
    </form>
{% endblock content %}

如果我们[访问http://localhost:8000/accounts/signup/,我们现在就可以看到漂亮的用户注册表,这真的是一个最小的努力。

django usercreationform output

这是UserCreationForm的默认实例所输出的Html。你不需要从头开始写所有的Html标记。

<form>
  <tr>
    <th><label for="id_username">Username:</label></th>
    <td><input type="text" name="username" maxlength="150" autocapitalize="none" autocomplete="username" autofocus required id="id_username">
      <br>
      <span class="helptext">Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.</span></td>
  </tr>
  <tr>
    <th><label for="id_password1">Password:</label></th>
    <td><input type="password" name="password1" autocomplete="new-password" required id="id_password1">
      <br>
      <span class="helptext">
      <ul>
        <li>Your password can’t be too similar to your other personal information.</li>
        <li>Your password must contain at least 8 characters.</li>
        <li>Your password can’t be a commonly used password.</li>
        <li>Your password can’t be entirely numeric.</li>
      </ul>
      </span></td>
  </tr>
  <tr>
    <th><label for="id_password2">Password confirmation:</label></th>
    <td><input type="password" name="password2" autocomplete="new-password" required id="id_password2">
      <br>
      <span class="helptext">Enter the same password as before, for verification.</span></td>
  </tr>
</form>

添加一个提交按钮

有一件事没有包含在表单生成中,那就是提交按钮。我们可以手动添加一个,就像我们在下面的代码中看到的那样。

{% extends "./layout/base.html" %}
{% load static %}

{% block content %}
    <h1>Signup</h1>
    <form action="/accounts/signup/" method="post">
        {{ form }}
        <input type="submit" value="Signup">
    </form>
{% endblock content %}

现在,我们有了整个表单,并准备好了提交按钮。

django usercreationform submit button


保存用户

现在我们要给**signup_view()**函数接线,以便它能检测到正在使用的表单提交动词,并根据它是POST请求还是GET请求采取适当的行动。在下面的代码中,如果检测到的是POST请求,那么我们就会把表单的内容存储到那个 **form**使用form = UserCreationForm(request.POST)这个变量。为了验证表单,你所要做的就是使用form.is_valid()。最后,如果验证通过,你可以用*form.save()保存用户,然后用return redirect('posts:list')*重定向到帖子的列表。else条件处理GET请求,并简单地创建一个空白表单并将其发送到注册模板。

accounts/views.py

from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm


# Create your views here.
def signup_view(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('posts:list')
    else:
        form = UserCreationForm()
    return render(request, 'accounts/signup.html', {'form': form})

CSRF Token

在我们尝试提交这个表单之前,我们需要确保我们包含一个csrf令牌来进行验证。csrf令牌可以确保发送到Django应用程序的请求是有效和安全的。要在Django表单中添加csrf令牌,可以使用模板标签,比如*{% csrf_token %}*。

{% extends "./layout/base.html" %}
{% load static %}

{% block content %}
    <h1>Signup</h1>
    <form action="/accounts/signup/" method="post">
        {% csrf_token %}
        {{ form }}
        <input type="submit" value="Signup">
    </form>
{% endblock content %}

首先,我们要尝试注册一个新用户,但我们可以使用一个坏的密码。

enter info usercreationform django

Djangos UserCreationForm的工作非常完美。它自动处理验证,并提供了如何解决问题的提示。非常好!

django form automatic validation

这一次,当我们提供符合所有要求的输入时,表单成功提交,我们被重定向,就像我们视图函数中的代码所设置的那样。

redirect after django form submit

事实上,这已经把我们的新用户保存到了数据库中。我们可以在管理区进行检查,看看,我们的新用户!

new user is saved to the database

请注意,当一个新用户通过前端创建时,它是一个具有有限权限的普通用户--这是很有意义的。

no admin rights for new users


显示一个认证表格

在这一点上,该表单正在应用程序中创建一个新的用户。然而,我们还没有把他们登录进去。此外,用户甚至没有办法尝试登录。这时我们就可以使用Django中的另一个魔法了,那就是**AuthenticationForm()**类。首先,我们需要一个新的路由、视图函数和模板来显示登录表单。

这里的代码设置了一个login/路由,指向**login_view()**函数,并命名为login
accounts/urls.py

from django.urls import path
from . import views

app_name = 'accounts'

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

下面突出显示的代码表明我们如何在views.py的login_view()函数中使用AuthenticationForm
accounts/views.py

from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm


# Create your views here.
def signup_view(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('posts:list')
    else:
        form = UserCreationForm()
    return render(request, 'accounts/signup.html', {'form': form})


def login_view(request):
    if request.method == 'POST':
        form = AuthenticationForm(data=request.POST)
        if form.is_valid():
            return redirect('posts:list')
    else:
        form = AuthenticationForm()
    return render(request, 'accounts/login.html', {'form': form})

最后,我们需要一个login.html模板来向用户显示一个登录表单。该表单在模板中的输出方式与我们使用UserCreationForm时相似。表单的动作是用模板标签和url函数设置的,是一个命名的路由。我们还包括一个csrf令牌,就像以前一样。

accounts/templates/accounts/login.html

{% extends "./layout/base.html" %}
{% load static %}

{% block content %}
    <h1>Log In</h1>
    <form action="{% url 'accounts:login' %}" method="post">
        {% csrf_token %}
        {{ form }}
        <input type="submit" value="Log In">
    </form>
{% endblock content %}

现在我们可以测试一下了。如果我们没有使用正确的凭证,表单会完美地工作并让我们知道。

log in with bad creds example

然而,一旦我们提供了正确的凭证,表单就会提交,并按照我们的要求重定向给我们。

good login then redirect


将用户登录到应用程序

在这一步,我们将添加代码来登录用户。在上面的步骤中,表单提交并重定向了我们,但实际与应用程序建立会话的代码还没有到位。下面突出显示的代码为我们完成了登录过程。

accounts/views.py

from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login


# Create your views here.
def signup_view(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            return redirect('posts:list')
    else:
        form = UserCreationForm()
    return render(request, 'accounts/signup.html', {'form': form})


def login_view(request):
    if request.method == 'POST':
        form = AuthenticationForm(data=request.POST)
        if form.is_valid():
            user = form.get_user()
            login(request, user)
            return redirect('posts:list')
    else:
        form = AuthenticationForm()
    return render(request, 'accounts/login.html', {'form': form})

一旦我们填写了登录表格并登录,我们可以通过访问管理区来检查我们的登录状态。它说我们事实上已经通过了验证,但我们没有权限以Sonic的身份进入管理区。这证明我们与应用程序的会话实际上已经建立。

Django user account login


如何注销一个用户

我们还需要有注销应用程序的能力。下面是我们如何设置的。首先,我们在urls.py文件中添加所需的路由。突出的一行定义了一个/logout路由,指向**logout_view()**函数,并命名为logout

accounts/urls.py

from django.urls import path
from . import views

app_name = 'accounts'

urlpatterns = [
    path('signup/', views.signup_view, name='signup'),
    path('login/', views.login_view, name='login'),
    path('logout/', views.logout_view, name='logout')
]

要注销一个用户,可以使用下面的高亮代码。它不需要一个实际的模板。它所做的只是检查用户是否向这个路由发送了POST请求,如果是,则调用**logout()**函数,同时传入 request.一旦完成,就直接重定向到帖子列表。Django很聪明,知道这是哪个用户,并将其注销。所有这些信息都包含在请求对象中。

accounts/views.py

from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login, logout


# Create your views here.
def signup_view(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            return redirect('posts:list')
    else:
        form = UserCreationForm()
    return render(request, 'accounts/signup.html', {'form': form})


def login_view(request):
    if request.method == 'POST':
        form = AuthenticationForm(data=request.POST)
        if form.is_valid():
            user = form.get_user()
            login(request, user)
            return redirect('posts:list')
    else:
        form = AuthenticationForm()
    return render(request, 'accounts/login.html', {'form': form})


def logout_view(request):
    if request.method == 'POST':
        logout(request)
        return redirect('posts:list')

显示注销按钮

我们应该向用户显示一个注销按钮,但前提是用户当前已经登录。Django给了我们一个很好的方法,使用用户对象上的is_authenticated属性来检查这个问题。你可以在你的Django模板中使用*{% if user.is_authenticated %}*引用它。所以在下面的代码中,注销按钮被用在一个表单标签中。这样我们就可以将按钮设置为轻松地发送一个POST请求来进行注销,这是一个最佳的做法。另外,请注意,这个表单/按钮只有在用户真正通过认证时才会显示。

posts/templates/posts/layout/base.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    {% load static %}
    <link rel="stylesheet" href="{% static "posts/css/bootstrap.min.css" %}">

    <title>Django Blog</title>
</head>
<body class="container mt-5">
<nav class="mb-3">
    {% if user.is_authenticated %}
        <form action="{% url 'accounts:logout' %}" method="post">
            {% csrf_token %}
            <button class="btn btn-primary btn-sm" type="submit">Log Out</button>
        </form>
    {% endif %}
</nav>
{% block content %}

{% endblock content %}
</body>
</html>

现在,当我们登录的时候,我们确实看到了注销的选项。

django useris_authenticated example

点击这个按钮,用户就会退出,并重定向到帖子列表。非常好!

log out and redirect django

如何用Django注册和登录用户 摘要

Django为你的Web应用提供了一个强大的认证系统。它涵盖了认证系统的所有最常见的用例,并使用了一些非常酷的类,如UserCreationFormAuthenticationForm