Skip to content

Django登录案例

更新: 2025/2/24 字数: 0 字 时长: 0 分钟

通过前面的学习,我们已经掌握了基本的Django使用,现在我们来实现一个登录的案例。

基本工作

添加路径

首先,在 urls.py 文件中添加对应的登录路径,代码如下:

python
path('login/', app01.views.login)

QQ截图20220514114424

添加视图

接下来,我们在 views.py 文件中添加login路径下的视图,代码如下:

python
def login(request):
    return render(request, 'login.html')

QQ截图20220514114737

添加模板

最后,我们在templates文件里面新建 login.html 页面文件,代码如下:

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>用户登录</h1>
<!-- 创建一个表单,发送方式是post,触发login视图函数 -->
<form method="post" action="/login/">
    <input type="text" name="user" placeholder="用户名">
    <input type="password" name="password" placeholder="密码">
    <input type="submit" value="提交">
</form>
</body>
</html>

QQ截图20220514115846

现在我们去访问 http://127.0.0.1:8000/login/ 出现如下页面,就说明准备工作没问题了。

QQ截图20220514120039

建立逻辑

区分请求

我们都已经知道,浏览器回车发起请求,是向 login 函数发送了一个GET请求,而通过上面的提交按钮发起的请求,是向 login 函数发送了一个POST请求,假如登录成功了,我们应该返回一个 登录成功 的信息。因此,视图函数的逻辑修改为如下代码:

python
def login(request):
    if request.method == 'GET':
        # GET请求返回登录页面
        return render(request, 'login.html')
    else:
        # POST请求返回登录成功
        return HttpResponse('登录成功')

QQ截图20220514120954

CSRF认证

现在我们访问 http://127.0.0.1:8000/login/ 随便输入用户名和密码,点击提交按钮:

QQ截图20220514121151

结果返回了如下页面,这是因Django默认会提供一个CSRF的保护机制,如果CSRF验证失败,请求会被禁止。

QQ截图20220514121256

这里简单讲一下,CSRF(跨站请求伪造)是一种常见的攻击手段。以我们的删除表单为例,某恶意网站的页面中内嵌了一段代码,访问时会自动发送一个删除某个电影条目的 POST 请求到我们的程序。如果我们访问了这个恶意网站,就会导致电影条目被删除,因为我们的程序没法分辨请求发自哪里。解决方法通常是在表单里添加一个包含随机字符串的隐藏字段,同时在 Cookie 中也创建一个同样的随机字符串,在提交时通过对比两个值是否一致来判断是否是用户自己发送的请求。

那么我们如何解决这个问题呢,也很简单,只需要在 login.html 页面的 form 表单中添加一行 {% csrf_token %} 即可解决,代码如下:

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>用户登录</h1>
<!-- 创建一个表单,发送方式是post,触发login视图函数 -->
<form method="post" action="/login/">
    <!-- 添加token令牌 -->
    {% csrf_token %}
    <input type="text" name="user" placeholder="用户名">
    <input type="password" name="password" placeholder="密码">
    <input type="submit" value="提交">
</form>
</body>
</html>

QQ截图20220514122456

现在我们我们输入用户名和密码,点击提交,就会给我们返回“登录成功”的字样了:

QQ截图20220514122628

获取表单

在视图函数的POST请求里面,并没有登录验证,而是直接返回“登录成功”的字样。现在我们要写登录功能,就必须拿到POST表单传递的用户名和密码,就可以使用前面学习的 request.POST 方法,代码修改如下:

python
def login(request):
    if request.method == 'GET':
        # GET请求返回登录页面
        return render(request, 'login.html')
    else:
        # 输出表单的全部信息
        print(f'POST表单:{request.POST}')
        # 因为html的用户名标签属性name="user",所以这里获取"user"
        print(f'用户名:{request.POST.get("user")}')
        # 因为html的密码标签属性name="password",所以这里获取"password"
        print(f'密码:{request.POST.get("password")}')
        # 获取token令牌值
        print(f'token令牌:{request.POST.get("csrfmiddlewaretoken")}')
        # POST请求返回登录成功
        return HttpResponse('登录成功')

QQ截图20220514123825

紧接着,我们访问 http://127.0.0.1:8000/login/ 随便输入用户名和密码,点击提交按钮:

QQ截图20220514121151

在控制台打印如下信息:

QQ截图20220514124110

登录功能

到这里,获取到表单中的用户名和密码信息,我们可以写登录功能了。修改 login 视图函数的POST请求逻辑如下:

python
def login(request):
    if request.method == 'GET':
        # GET请求返回登录页面
        return render(request, 'login.html')
    else:
        # 验证表单用户和密码
        if request.POST.get("user") == "root" and request.POST.get("password") == "123":
            # 登录成功
            return HttpResponse('登录成功')
        else:
            # 登录失败
            return HttpResponse('登录失败')

我们访问 http://127.0.0.1:8000/login/ 输入错误的用户名和密码,点击提交按钮,返回登录失败:

QQ截图20220514125335

错误提示

但为追求人性化的设计,在输入错误的用户名和密码的情况,网站通常不会返回一个错误页面,而是让你停留在当前页面只返回一个错误提示。

接下来修改 login.html 页面,增加错误提示,代码如下:

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>用户登录</h1>
<!-- 创建一个表单,发送方式是post,触发login视图函数 -->
<form method="post" action="/login/">
    <!-- 添加token令牌 -->
    {% csrf_token %}
    <input type="text" name="user" placeholder="用户名">
    <input type="password" name="password" placeholder="密码">
    <input type="submit" value="提交">
    <!-- 错误提示标签 -->
    <span style="color: red;">{{ error_msg }}</span>
</form>
</body>
</html>

QQ截图20220514130554

现在我们去访问 http://127.0.0.1:8000/login/ 页面,虽然 login 视图函数中的GET请求没有给login页面传递 error_msg 值,但依然会加载 <span> 标签:

QQ截图20220514131207

现在,修改 login 视图函数的POST请求逻辑如下:

python
def login(request):
    if request.method == 'GET':
        # GET请求返回登录页面
        return render(request, 'login.html')
    else:
        # 验证表单用户和密码
        if request.POST.get("user") == "root" and request.POST.get("password") == "123":
            # 登录成功
            return HttpResponse('登录成功')
        else:
            # 登录失败
            return render(request, 'login.html', {'error_msg': '用户名或密码错误'})

QQ截图20220514131416

现在,我们访问 http://127.0.0.1:8000/login/ 输入错误的用户名和密码,点击提交按钮,就会提示一个用户名和密码错误:

QQ截图20220514131559

代码优化

上面的代码中我们用了比较多的 if else 嵌套,可以优化代码如下:

python
def login(request):
    if request.method == 'GET':
        # GET请求返回登录页面
        return render(request, 'login.html')

    # 验证表单用户和密码
    if request.POST.get("user") == "root" and request.POST.get("password") == "123":
        # 登录成功
        return HttpResponse('登录成功')

    # 登录失败
    return render(request, 'login.html', {'error_msg': '用户名或密码错误'})