Django项目(可重用注册登录系统+邮箱验证)

可重用注册登录系统

项目最终代码: https://bitbucket.org/lvah/loginregister
注册(邮箱注册,手机,微信,QQ)
登录
注销

创建Django项目

在这里插入图片描述

创建app

 python manage.py startapp login

创建成功后,会出现下面的文件
在这里插入图片描述

设置时区和语言

在这里插入图片描述

数据库表生成

$ python manage.py migrate # 将迁移脚本的内容写入数据库并创建数据库表
$ python manage.py createsuperuser # 创建后台登录的超级用户

启动开发服务器

方法一:

python manage.py runserver 9999;

方法二:
在这里插入图片描述
在这里插入图片描述
此时直接点击run就可以运行
在这里插入图片描述
浏览器访问,检测是否成功?
访问网址: http://127.0.0.1:9999/
访问网址: http://127.0.0.1:9999/admin/
在这里插入图片描述

git提交项目代码到本地仓库

$ git init
# 安装插件.ignore, 并生成python上传git项目需要忽略内容的文件.gitignore
$ git add * # 添加修改到暂存区
$ git commit -m "搭建项目开发环境" # 将暂存区的代码提交到本地git仓库
$ git log # 查看历史提交记录

安装插件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

设置数据库模型

作为一个用户登录和注册项目,需要保存的都是各种用户的相关信息。很显然,我们至少需要一张用户
表User,在用户表里需要保存下面的信息:
用户名(name): 必填,最长不超过128个字符且唯一(unique)
密码(password): 必填,最长不超过256个字符
邮箱地址(email): 使用Django内置的邮箱类型且唯一
性别(gender): 性别, 使用choice,只能选择男或者女或者未知,默认为未知;
创建时间(create_time): 用户创建时间
注意点: auto_now_add=True时为添加时的时间,更新对象时不会有变动。
git init #安装插件.ignore, 并生成python上传git项目需要忽略内容的文件.gitignore
git add * # 添加修改到暂存区
git commit -m “搭建项目开发环境” # 将暂存区的代码提交到本地git仓库
git log # 查看历史提交记录
修改时间(modify_time):用户最后一次修改时间
注意点: auto_now=True无论是你添加还是修改对象,时间为你添加或者修改的时间。
最后一次登录时间(last_login_time): 最后一次登录时间
注意点:null=True的话,数据库中该字段是NULL,即允许空值
注意点:blank=False(默认)的话,字段没被赋值则会抛错;和数据验证(表单验证等)有

数据库模型文件

# login/models.py
from django.db import models
# Create your models here.
# appname_siteuser
class SiteUser(models.Model):
"""用户的数据库模型,注册/登录需要"""
gender_choice = (
(0, "未知"),
(1, "男"),
(2, "女"),
)
name = models.CharField(max_length=128, unique=True, verbose_name="用户名")
password = models.CharField(max_length=256, verbose_name="密码")
email = models.EmailField(unique=True, verbose_name="电子邮箱")
gender = models.IntegerField(choices=gender_choice, default=0,
verbose_name="性别")
# auto_now_add=True时为添加时的时间,更新对象时不会有变动。
# auto_now=True无论是你添加还是修改对象,时间为你添加或者修改的时间。
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时
间")
modify_time = models.DateTimeField(auto_now=True, verbose_name="最后一次修改时
间")
# null针对数据库层面的, blank针对表单的
last_login_time = models.DateTimeField(null=True, blank=True,
verbose_name="最后一次登录时间")
def __str__(self):
return self.name
class Meta:
verbose_name = "网站用户管理"
verbose_name_plural = verbose_name;

在这里插入图片描述

设置数据库后端

Django支持MySQL, Sqlite, oracle等数据库, 此处选择默认的sqlite,不做修改。

注册app

# loginRegister/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'login', # 修改的内容
]

在这里插入图片描述

生成迁移脚本并写入数据库

$ python manage.py migrate # 将迁移脚本的内容写入数据库并创建数据库表
$ python manage.py createsuperuser # 创建后台登录的超级用户

在这里插入图片描述

测试是否成功

打开数据库文件db.sqlite3, 查看是否有数据库表login_siteuser,如果有,则操作成功。
在这里插入图片描述

数据库模型后台管理

# login/admin.py
from django.contrib import admin
from login.models import SiteUser
# Register your models here.
# 后台管理设置的信息
class SiteUserAdmin(admin.ModelAdmin):
list_display = ['name', 'gender', 'email']
list_display_links = ['name']
list_filter = ['gender', 'create_time']
list_per_page = 10
admin.site.register(SiteUser, SiteUserAdmin)

路由与视图函数框架搭建

路由设计

访问策略:
未登录人员,不论是访问index还是login和logout,全部跳转到login界面
已登录人员,访问login会自动跳转到index页面
已登录人员,不允许直接访问register页面,需先logout
登出后,自动跳转到login界面

路由配置

主路由配置文件

# loginRegister/urls.py
from django.urls import path, include
from login import views

urlpatterns = [
    path('index/', views.index, name='index'),
    path('login/', views.login, name='login'),
    path('register/', views.register, name='register'),
    path('logout/', views.logout, name='logout'),
]

在这里插入图片描述
子路由配置文件(login子应用的)

# login/urls.py(新建的文件)
from django.urls import path, include
from login import views
urlpatterns = [
path('index/', views.index, name='index'),
path('login/', views.login, name='login'),
path('register/', views.register, name='register'),
path('logout/', views.logout, name='logout'),
]

在这里插入图片描述

视图函数的配置

# login/views.py
from django.shortcuts import render, redirect
# Create your views here.
def index(request):
pass
return render(request, 'login/index.html')
def login(request):
pass
return render(request, 'login/login.html')
def register(request):
pass
return render(request, 'login/register.html')
def logout(request):
pass
# redirect: 重定向(跳转)
return redirect('/login/')

在这里插入图片描述

模板template的配置

templates/login/index.html(新建)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>这是首页的模拟界面</h1>
</body>
</html>

在这里插入图片描述
templates/login/login.html(新建)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h1>用户登录</h1>
<form>
用户名: <input type="text" placeholder="username"><br/>
密码: <input type="password" placeholder="password"><br/>
<input type="submit" value="登录">
</form>
</body>
</html>

在这里插入图片描述
templates/login/register.html(新建)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册界面</title>
</head>
<body>
<h1>用户注册</h1>
<form>
用户名: <input type="text" placeholder="username"><br/>
电子邮箱: <input type="email" placeholder="email"><br/>
密码: <input type="password" placeholder="password"><br/>
确认密码: <input type="password" placeholder="password"><br/>
<input type="submit" value="注册">
</form>
</body>
</html>

在这里插入图片描述

测试是否成功

浏览器访问,检测是否成功?
访问网址: http://127.0.0.1:9999/index/
在这里插入图片描述
访问网址: http://127.0.0.1:9999/login/
在这里插入图片描述

访问网址: http://127.0.0.1:9999/register/
在这里插入图片描述

前端界面设计及优化

templates/login/index.html

<!doctype html>
<html lang="zh-CN">
  <head>
    <!-- 必须的 meta 标签 -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap 的 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>首页</title>
  </head>
  <body>
    <h1>这是首页的模拟界面</h1>

    <!-- JavaScript 文件是可选的。从以下两种建议中选择一个即可! -->

    <!-- 选项 1:jQuery 和 Bootstrap 集成包(集成了 Popper) -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV" crossorigin="anonymous"></script>

    <!-- 选项 2:Popper 和 Bootstrap 的 JS 插件各自独立 -->
    <!--
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
    -->
  </body>
</html>

templates/login/login.html

<!doctype html>
<html lang="zh-CN">
<head>
    <!-- 必须的 meta 标签 -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap 的 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>用户登录</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-sm">

        </div>
        <div class="col-sm">
            <h3 style="text-align: center">用户登录</h3>
            <div class="alert alert-warning" role="alert">
                <strong>登录失败!</strong> 用户密码错误!
            </div>

            <form>
                <div class="form-group">
                    <label>用户名</label>
                    <input type="text" class="form-control">
                </div>
                <div class="form-group">
                    <label>Password</label>
                    <input type="password" class="form-control">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <a href="/register/" class="text-success">
                    <ins>新用户注册</ins>
                </a>
                <button type="submit" class="btn btn-primary float-right">登录</button>
            </form>

        </div>
        <div class="col-sm">

        </div>
    </div>
</div>
<!-- JavaScript 文件是可选的。从以下两种建议中选择一个即可! -->

<!-- 选项 1:jQuery 和 Bootstrap 集成包(集成了 Popper) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV"
        crossorigin="anonymous"></script>

<!-- 选项 2:Popper 和 Bootstrap 的 JS 插件各自独立 -->
<!--
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
-->
</body>
</html>

templates/login/register.html

<!doctype html>
<html lang="zh-CN">
<head>
    <!-- 必须的 meta 标签 -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap 的 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>注册界面</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-sm">

        </div>
        <div class="col-sm">
            <h3 style="text-align: center">用户注册</h3>
            <form>
                <div class="form-group">
                    <label>用户名</label>
                    <input type="text" class="form-control">
                </div>
                <div class="form-group">
                    <label>电子邮箱</label>
                    <input type="email" class="form-control">
                </div>
                <div class="form-group">
                    <label>密码</label>
                    <input type="password" class="form-control">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <div class="form-group">
                    <label>确认密码</label>
                    <input type="password" class="form-control">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <a href="/login/" class="text-success">
                    <ins>用户登录</ins>
                </a>
                <button type="submit" class="btn btn-primary float-right">注册</button>
            </form>

        </div>
        <div class="col-sm">

        </div>
    </div>
</div>
<!-- JavaScript 文件是可选的。从以下两种建议中选择一个即可! -->

<!-- 选项 1:jQuery 和 Bootstrap 集成包(集成了 Popper) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV"
        crossorigin="anonymous"></script>

<!-- 选项 2:Popper 和 Bootstrap 的 JS 插件各自独立 -->
<!--
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
-->
</body>
</html>

测试
在这里插入图片描述
在这里插入图片描述

完善登录的视图函数

html和视图函数交互的完善
修改1. 有message信息则显示, 没有就不显示。
修改2: 提交登录信息时, 以post方法提交给/login/对应的是视图函数处理。
修改3: Django提供了csrf防攻击的机制, 添加该信息则可顺利访问登陆界面
修改4:name="username"指定表单内容存储的key值名称, eg: {“username”:“你填的用户
名”,“password”:“你填的密码” }

login文件的完善

# templates/login/login.html
<!doctype html>
<html lang="zh-CN">
<head>
    <!-- 必须的 meta 标签 -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap 的 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>用户登录</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-sm">

        </div>
        <div class="col-sm">
            <h3 style="text-align: center">用户登录</h3>
            {% if message %}
            <div class="alert alert-warning" role="alert">
                <strong>登录失败!</strong> {{ message }}
            </div>
            {% endif %}

            <form action="/login/" method="post">
                {% csrf_token %}
                <div class="form-group">
                    <label>用户名</label>
                    <input type="text" class="form-control" name="username">
                </div>
                <div class="form-group">
                    <label>Password</label>
                    <input type="password" class="form-control" name="password">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <a href="/register/" class="text-success">
                    <ins>新用户注册</ins>
                </a>
                <button type="submit" class="btn btn-primary float-right">登录</button>
            </form>

        </div>
        <div class="col-sm">

        </div>
    </div>
</div>
<!-- JavaScript 文件是可选的。从以下两种建议中选择一个即可! -->

<!-- 选项 1:jQuery 和 Bootstrap 集成包(集成了 Popper) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV"
        crossorigin="anonymous"></script>

<!-- 选项 2:Popper 和 Bootstrap 的 JS 插件各自独立 -->
<!--
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
-->
</body>
</html>

视图函数的完善

# login/views.py
from django.shortcuts import render, redirect
from login.models import SiteUser
# Create your views here.

def index(request):
    pass
    return render(request, 'login/index.html')

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username').strip()
        password = request.POST.get('password').strip()
        print(username, password)
        print(request.POST)
        if username and password:
            user = SiteUser.objects.filter(name=username, password=password).first()
            if user:
                return redirect('/index/')
            else:
                message = "用户名或者密码错误"
                return render(request, 'login/login.html', {'message':message})
        else:
            message = "非法的数据信息"
            return render(request, 'login/login.html', {'message': message})
    return render(request, 'login/login.html')

def register(request):
    pass
    return render(request, 'login/register.html')

def logout(request):
    pass
    #redirect:重定向(跳转)
    return redirect('/login/')

浏览器访问,检测是否成功?

访问网址: http://127.0.0.1:9999/login/
填写正确的用户名和密码后会跳转到index界面,错误的用户名和密码会报错

session会话与登录的视图函数

视图函数

# login/views.py
from django.shortcuts import render, redirect

# Create your views here.
from login.models import SiteUser


def index(request):
    pass
    return render(request, 'login/index.html')

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username').strip()
        password = request.POST.get('password').strip()
        # print(username, password)
        if username and password:
            user = SiteUser.objects.filter(name=username, password=password).first()
            if user:
                request.session['is_login'] = True
                request.session['user_id'] = user.id
                request.session['username'] = user.name
                return  redirect('/index/')
            else:
                message = "用户名或者密码错误"
                return  render(request, 'login/login.html', {'message':message})
        else:
            message = "非法的数据信息"
            return render(request, 'login/login.html', {'message': message})
    return render(request, 'login/login.html')

def register(request):
    pass
    return render(request, 'login/register.html')

def logout(request):
    pass
    # redirect: 重定向(跳转)
    return redirect('/login/')
    # 如果状态不是登录状态,则无法登出。
    if request.session.get('is_login'):
        request.session.flush()  # 清空session信息
    return  redirect('/login/')

index文件

# templates/login/index.html
<!doctype html>
<html lang="zh-CN">
  <head>
<head>
    <!-- 必须的 meta 标签 -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap 的 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>首页</title>
  </head>
  <body>
    <h1>这是首页的模拟界面</h1>

    <!-- JavaScript 文件是可选的。从以下两种建议中选择一个即可! -->

    <!-- 选项 1:jQuery 和 Bootstrap 集成包(集成了 Popper) -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV" crossorigin="anonymous"></script>

    <!-- 选项 2:Popper 和 Bootstrap 的 JS 插件各自独立 -->
    <!--
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
    -->
  </body>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <a class="navbar-brand" href="#">主页</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
                <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="#">Link</a>
            </li>
            <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
                   aria-haspopup="true" aria-expanded="false">
                    Dropdown
                </a>
                <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                    <a class="dropdown-item" href="#">Action</a>
                    <a class="dropdown-item" href="#">Another action</a>
                    <div class="dropdown-divider"></div>
                    <a class="dropdown-item" href="#">Something else here</a>
                </div>
            </li>
            <li class="nav-item">
                <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
            </li>
        </ul>
        <form class="form-inline my-2 my-lg-0">
            <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
            <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
        </form>
        <ul class="navbar-nav">
            <li class="nav-item">
                <a class="nav-link" href="/logout/">登出</a>
            </li>

            <li class="nav-item">
                <a class="nav-link" href="/index/">{{ request.session.username }}</a>
            </li>
        </ul>
    </div>
</nav>

<h1>你好, {{ request.session.username }}, 这是首页的模拟界面</h1>


<!-- JavaScript 文件是可选的。从以下两种建议中选择一个即可! -->

<!-- 选项 1:jQuery 和 Bootstrap 集成包(集成了 Popper) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV"
        crossorigin="anonymous"></script>

<!-- 选项 2:Popper 和 Bootstrap 的 JS 插件各自独立 -->
<!--
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
-->
</body>
</html>

测试

在这里插入图片描述

登录成功后,就会出现以下界面
在这里插入图片描述

图片验证码

为了防止机器人频繁登录网站或者破坏分子恶意登录,很多用户登录和注册系统都提供了图形验证码功能。在Django中实现图片验证码功能非常简单,有现成的第三方库可以使用,我们不必自己开发(不必重复造轮子)。这个库叫做django-simple-captcha。
具体安装教程:https://django-simple-captcha.readthedocs.io/en/latest/usage.html

Django表单

我们前面都是手工在HTML文件中编写表单form元素,然后在views.py的视图函数中接收表单中的用户数据,再编写验证代码进行验证,最后使用ORM进行数据库的增删改查。这样费时费力,整个过程比较复杂,而且有可能写得不太恰当,数据验证也比较麻烦。设想一下,如果我们的表单拥有几十上百个数据字段,有不同的数据特点,如果也使用手工的方式,其效率和正确性都将无法得到保障。有鉴于此,Django在内部集成了一个表单功能,以面向对象的方式,直接使用Python代码生成HTML表单代码,专门帮助我们快速处理表单相关的内容。Django的表单给我们提供了下面三个主要功能:
1.准备和重构数据用于页面渲染;
2.为数据创建HTML表单元素;
3.接收和处理用户从表单发送过来的数据。
编写Django的form表单,非常类似我们在模型系统里编写一个模型。在模型中,一个字段代表数据表的一列,而form表单中的一个字段代表 form 中的一个 input 元素。

创建表单模型

# /login/forms.py(新建的文件)
from captcha.fields import CaptchaField
from django import forms
class LoginForm(forms.Form):
    username = forms.CharField(label='用户名', required=True,
                               min_length=4, max_length=128)
    password = forms.CharField(label="密码", required=True,
                               min_length=4, max_length=10)
    captcha = CaptchaField(label="验证码")

视图逻辑优化

# login/views.py
from django.shortcuts import render, redirect

# Create your views here.
from login.forms import LoginForm
from login.models import SiteUser


def index(request):
    pass
    return render(request, 'login/index.html')

def login(request):
    if request.method == 'POST':
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            username = login_form.cleaned_data.get('username')
            password = login_form.cleaned_data.get('password')
            user = SiteUser.objects.filter(name=username, password=password).first()
            if user:
                request.session['is_login'] = True
                request.session['user_id'] = user.id
                request.session['username'] = user.name
                return  redirect('/index/')
            else:
                message = "用户名或者密码错误"
                return  render(request, 'login/login.html', locals())
        else:
            message = "填写的登录信息不合法"
            return render(request, 'login/login.html', locals())
    login_form = LoginForm()
    return render(request, 'login/login.html', locals())

def register(request):
    pass
    return render(request, 'login/register.html')

def logout(request):
    # 如果状态不是登录状态,则无法登出。
    if request.session.get('is_login'):
        request.session.flush()  # 清空session信息
    return  redirect('/login/')

Template页面优化

# templates/login/login.html
<!doctype html>
<html lang="zh-CN">
<head>
    <!-- 必须的 meta 标签 -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap 的 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>用户登录</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-sm">

        </div>
        <div class="col-sm">
            <h3 style="text-align: center">用户登录</h3>
            {% if login_form.captcha.errors %}
                <div class="alert alert-warning" role="alert">
                    <strong>登录失败!</strong> 验证码不正确
                </div>
            {% elif message %}
                <div class="alert alert-warning" role="alert">
                    <strong>登录失败!</strong> {{ message }}
                </div>
            {% endif %}

            <form action="/login/" method="post">
                {% csrf_token %}
                <div class="form-group">
                    <label>{{ login_form.username.label }}</label>
                    <input type="text" class="form-control" name="username">
                </div>
                <div class="form-group">
                    <label>{{ login_form.password.label }}</label>
                    <input type="password" class="form-control" name="password">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <div class="form-group">
                    <label>{{ login_form.captcha.label }}</label>
                    {{ login_form.captcha }}
                </div>
                <a href="/register/" class="text-success">
                    <ins>新用户注册</ins>
                </a>
                <button type="submit" class="btn btn-primary float-right">登录</button>
            </form>

        </div>
        <div class="col-sm">

        </div>
    </div>
</div>
<!-- JavaScript 文件是可选的。从以下两种建议中选择一个即可! -->

<!-- 选项 1:jQuery 和 Bootstrap 集成包(集成了 Popper) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV"
        crossorigin="anonymous"></script>

<!-- 选项 2:Popper 和 Bootstrap 的 JS 插件各自独立 -->
<!--
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
-->
</body>
</html>

验证

当账号、密码、验证码都正确时
在这里插入图片描述
在这里插入图片描述
当验证码错误时
在这里插入图片描述
当密码错误时
在这里插入图片描述

邮箱注册

配置邮件信息

# loginRegister/settings.py
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = 'y15291204001@163.com' # 你的邮箱地址
EMAIL_HOST_PASSWORD = 'IFOQWWSUXPSJUSAP' # 不是邮箱的登录密码,而是授权码
EMAIL_USE_SSL = False

如何获取授权码?

在这里插入图片描述
在这里插入图片描述

交互式环境中测试发送邮件是否成功?

(venv) E:\loginRegister>python manage.py shell #进入交互式环境
In [1]: from django.core.mail import send_mail #导入模块
In [2]: from loginRegister.settings import EMAIL_HOST_USER #导入模块
In [3]: send_mail("测试邮件", "content", EMAIL_HOST_USER,['y15291204001@163.com']) #发送测试邮件
Out[3]: 1 #当返回值为1时,表示发送成功

验证

在这里插入图片描述

注册表单

# login/forms.py
class LoginForm(forms.Form):
    username = forms.CharField(label='用户名', required=True,
                               min_length=4, max_length=128)
    password = forms.CharField(label="密码", required=True,
                               min_length=4, max_length=10)
    captcha = CaptchaField(label="验证码")


class RegisterForm(forms.Form):
    username = forms.CharField(label="用户名", required=True, max_length=128)
    password1 = forms.CharField(label="密码", max_length=256, required=True)
    password2 = forms.CharField(label="确认密码", max_length=256, required=True)
    email = forms.EmailField(label="邮箱地址")
    captcha = CaptchaField(label='验证码')

实现注册视图

1.如果用户已经登录,则不能注册跳转到首页。
2.如果是GET请求,返回用户注册的html页面。
3.如果是POST请求, 先验证提交的数据是否通过,清洗数据。 接下来判断用户名和邮箱是否已经被注册, 将注册的信息存储到数据库,跳转到登录界面。
4.额外功能: 为了数据的安全性注册时,密码存储到数据库不是明文存储,而是先加密再存储

# login/views.py
def index(request):
    pass
    return render(request, 'login/index.html')

def login(request):
    if request.method == 'POST':
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            username = login_form.cleaned_data.get('username')
            password = login_form.cleaned_data.get('password')
            user = SiteUser.objects.filter(name=username, password=password).first()
            if user:
                request.session['is_login'] = True
                request.session['user_id'] = user.id
                request.session['username'] = user.name
                return  redirect('/index/')
            else:
                message = "用户名或者密码错误"
                return  render(request, 'login/login.html', locals())
        else:
            message = "填写的登录信息不合法"
            return render(request, 'login/login.html', locals())
    login_form = LoginForm()
    return render(request, 'login/login.html', locals())

def register(request):
    # 如果用户已经登录,则不能注册跳转到首页。
    if request.session.get('is_login', None):
        return redirect('/index/')
    # 如果是POST请求
    if request.method == 'POST':
        print(request.POST)
        register_form = RegisterForm(request.POST)
        message = "请检查填写的内容!"
        # 先验证提交的数据是否通过
        if register_form.is_valid():
            # 清洗数据
            username = register_form.cleaned_data.get('username')
            password1 = register_form.cleaned_data.get('password1')
            password2 = register_form.cleaned_data.get('password2')
            email = register_form.cleaned_data.get('email')

            print(locals())
            # 接下来判断用户名和邮箱是否已经被注册
            same_name_user = SiteUser.objects.filter(name=username)
            print(same_name_user)
            if same_name_user:
                message = '用户名已经存在'
                return render(request, 'login/register.html', locals())
            same_email_user = SiteUser.objects.filter(email=email)
            if same_email_user:
                message = '该邮箱已经被注册了!'
                return render(request, 'login/register.html', locals())
            # 将注册的信息存储到数据库,跳转到登录界面
            new_user = SiteUser(name=username, password=password1, email=email)
            new_user.save()
            return  redirect('/login/')
    # 如果是GET请求,返回用户注册的html页面。
    register_form = RegisterForm()
    return render(request, 'login/register.html', locals())


def logout(request):
    # 如果状态不是登录状态,则无法登出。
    if request.session.get('is_login'):
        request.session.flush()  # 清空session信息
    return  redirect('/login/')

Template模板的更改

# templates/login/register.html
<!doctype html>
<html lang="zh-CN">
<head>
    <!-- 必须的 meta 标签 -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap 的 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>注册界面</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-sm">
        </div>
        <div class="col-sm">
            <h3 style="text-align: center">用户注册</h3>
            {% if register_form.captcha.errors %}
                <div class="alert alert-warning" role="alert">
                    <strong>注册失败!</strong> 验证码不正确
                </div>
            {% elif message %}
                <div class="alert alert-warning" role="alert">
                    <strong>注册失败!</strong> {{ message }}
                </div>
            {% endif %}
            <form action="/register/" method="post">
                {% csrf_token %}
                <div class="form-group">
                    <label>{{ register_form.username.label }}</label>
                    <input type="text" class="form-control" name="username">
                </div>
                <div class="form-group">
                    <label>{{ register_form.email.label }}</label>
                    <input type="email" class="form-control" name="email">
                </div>
                <div class="form-group">
                    <label>{{ register_form.password1.label }}</label>
                    <input type="password" class="form-control" name="password1">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <div class="form-group">
                    <label>{{ register_form.password2.label }}</label>
                    <input type="password" class="form-control" name="password2">
                    <small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
                </div>
                <div class="form-group">
                    <label>{{ register_form.captcha.label }}</label>
                    {{ register_form.captcha }}
                </div>
                <a href="/login/" class="text-success">
                    <ins>用户登录</ins>
                </a>
                <button type="submit" class="btn btn-primary float-right">注册</button>
            </form>

        </div>
        <div class="col-sm">

        </div>
    </div>
</div>
<!-- JavaScript 文件是可选的。从以下两种建议中选择一个即可! -->

<!-- 选项 1:jQuery 和 Bootstrap 集成包(集成了 Popper) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV"
        crossorigin="anonymous"></script>

<!-- 选项 2:Popper 和 Bootstrap 的 JS 插件各自独立 -->
<!--
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
-->
</body>
</html>

测试

当有用户登录时
点击注册会跳转到index界面
在这里插入图片描述
此时点击登出,就可注册用户
在这里插入图片描述
在这里插入图片描述
注册成功后就可登录
在这里插入图片描述
在这里插入图片描述
此时可以在database中看到注册的信息
在这里插入图片描述

注册添加密码加密功能

对于如何加密密码,有很多不同的途径,其安全程度也高低不等。这里我们使用Python内置的hashlib库,使用哈希值的方式加密密码,可能安全等级不够高,但足够简单,方便使用。

在 login/utils.py 中编写一个hash函数:

def hash_code(s, salt='mysite'):# 加点盐
h = hashlib.sha256()
s += salt
h.update(s.encode()) # update方法只接收bytes类型
return h.hexdigest()

在 login/views.py 中修改login和register视图

def register(request):
# .....省略部分代码
new_user = SiteUser(name=username, password=hash_code(password1),
email=email)
# .....省略部分代码
def login(request):
# .....省略部分代码
user = SiteUser.objects.filter(name=username,
password=hash_code(password)).first()
# .....省略部分代码

邮件注册确认

很自然地,我们会想到如果能用邮件确认的方式对新注册用户进行审查,既安全又正式,也是目前很多站点的做法。

创建模型

既然要区分通过和未通过邮件确认的用户,那么必须给用户添加一个是否进行过邮件确认的属性。另外,我们要创建一张新表,用于保存用户的确认码以及注册提交的时间。

# /login/models.py
from django.db import models

# Create your models here.

# appname_siteuser
class SiteUser(models.Model):
    """用户的数据库模型,注册/登录需要"""
    gender_choice = (
        (0, "未知"),
        (1, "男"),
        (2, "女"),
    )
    name = models.CharField(max_length=128, unique=True, verbose_name="用户名")
    password = models.CharField(max_length=256, verbose_name="密码")
    email = models.EmailField(unique=True, verbose_name="电子邮箱")
    gender = models.IntegerField(choices=gender_choice, default=0, verbose_name="性别")
    # auto_now_add=True时为添加时的时间,更新对象时不会有变动。
    # auto_now=True无论是你添加还是修改对象,时间为你添加或者修改的时间。
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    modify_time = models.DateTimeField(auto_now=True, verbose_name="最后一次修改时间")
    # null针对数据库层面的, blank针对表单的
    last_login_time = models.DateTimeField(null=True, blank=True,
                                           verbose_name="最后一次登录时间")
    has_confirmed = models.BooleanField(default=False, verbose_name="是否邮箱验证")
    def __str__(self):
        return  self.name

    class Meta:
        verbose_name = "网站用户管理"
        verbose_name_plural = verbose_name

class ConfirmString(models.Model):
    code = models.CharField(max_length=256, verbose_name="确认码")
    user = models.OneToOneField('SiteUser', on_delete=models.CASCADE)
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")

    def __str__(self):
        return self.user.name + ":" + self.code

    class Meta:
        ordering = ["-create_time"]
        verbose_name = "确认码"
        verbose_name_plural = "确认码"

数据库模型更改,一定要生成迁移脚本和写入数据库。

python manage.py makemigrations
python manage.py migrate

修改视图

# /login/views.py
def index(request):
    pass
    return render(request, 'login/index.html')

def login(request):
    if request.method == 'POST':
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            username = login_form.cleaned_data.get('username')
            password = login_form.cleaned_data.get('password')
            user = SiteUser.objects.filter(name=username, password=hash_code(password)).first()
            if user:
                request.session['is_login'] = True
                request.session['user_id'] = user.id
                request.session['username'] = user.name
                return  redirect('/index/')
            else:
                message = "用户名或者密码错误"
                return  render(request, 'login/login.html', locals())
        else:
            message = "填写的登录信息不合法"
            return render(request, 'login/login.html', locals())
    login_form = LoginForm()
    return render(request, 'login/login.html', locals())

def register(request):
    # 如果用户已经登录,则不能注册跳转到首页。
    if request.session.get('is_login', None):
        return redirect('/index/')
    # 如果是POST请求
    if request.method == 'POST':
        print(request.POST)
        register_form = RegisterForm(request.POST)
        message = "请检查填写的内容!"
        # 先验证提交的数据是否通过
        if register_form.is_valid():
            # 清洗数据
            username = register_form.cleaned_data.get('username')
            password1 = register_form.cleaned_data.get('password1')
            password2 = register_form.cleaned_data.get('password2')
            email = register_form.cleaned_data.get('email')

            # 接下来判断用户名和邮箱是否已经被注册
            same_name_user = SiteUser.objects.filter(name=username)
            print(same_name_user)
            if same_name_user:
                message = '用户名已经存在'
                return render(request, 'login/register.html', locals())
            same_email_user = SiteUser.objects.filter(email=email)
            if same_email_user:
                message = '该邮箱已经被注册了!'
                return render(request, 'login/register.html', locals())
            try:
                # 将注册的信息存储到数据库,跳转到登录界面
                new_user = SiteUser(name=username, password=hash_code(password1), email=email)
                new_user.save()
                # 生成确认码并发送确认邮件
                code = make_confirm_string(new_user)
                print('code:', code)
                send_email(email, code)
                message = '请前往邮箱进行确认!'
            except Exception as e:
                new_user.delete()
                message = '发送邮件失败!'
                print(e)
                return render(request, 'login/register.html', locals())
            else:
                return  redirect('/login/')
    # 如果是GET请求,返回用户注册的html页面。
    register_form = RegisterForm()
    return render(request, 'login/register.html', locals())


def logout(request):
    # 如果状态不是登录状态,则无法登出。
    if request.session.get('is_login'):
        request.session.flush()  # 清空session信息
    return  redirect('/login/')

最后的有效期天数为设置在settings中的 CONFIRM_DAYS 。下面是邮件相关的settings配置:

# 注册有效期天数
CONFIRM_DAYS = 3

测试

在注册后会向邮箱发送确认邮件
在这里插入图片描述
查看注册信息,可以看到user5的密码也进行了加密
在这里插入图片描述

处理邮件确认

在login子应用的 urls.py 中添加一条url:

path('confirm/', views.user_confirm,name='confirm'),

其次,在 login/views.py 中添加一个 user_confirm 视图

获取确认码信息
数据库中是否有该确认码,如果没有, 返回说是无效的请求
数据库中是否有该确认码,如果有, 判断是否过期? 如果过期,删除用户信息,否则更新用户信息。

def user_confirm(request):
code = request.GET.get('code', None)
message = ''
try:
confirm = ConfirmString.objects.get(code=code)
except:
message = '无效的确认请求!'
return render(request, 'login/confirm.html', locals())
create_time = confirm.create_time
now = datetime.now()
print(now, create_time, create_time + timedelta(settings.CONFIRM_DAYS))
if now > create_time + timedelta(settings.CONFIRM_DAYS):
confirm.user.delete()
message = '您的邮件已经过期!请重新注册!'
else:
confirm.user.has_confirmed = True
confirm.user.save()
confirm.delete()
message = '感谢确认,请使用账户登录!'
return render(request, 'login/confirm.html', locals())

需要一个 confirm.html 页面,我们将它创建在 /login/templates/login/ 下面:

# /login/templates/login/confirm.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 style="margin-left: 100px;">{{ message }}</h1>

<script>
window.setTimeout("window.location='/login/'",2000);
</script>

</body>
</html>

测试

在注册后会向绑定的邮箱发送确认邮件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
此时就可以进行登录
在这里插入图片描述
以上就是重用登录系统开发过程,有些许不足。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值