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: 好的,这是一个使用 Django 和 Vue 实现登录注册功能的项目的简要步骤: 1. 使用 Django 创建一个新的项目,并启用 Django 自带的用户认证系统。 2. 创建一个应用程序,负责处理用户注册和登录功能。 3. 使用 Django Rest Framework (DRF) 创建 API 来处理前端 Vue 发送的注册和登录请求。 4. 使用 Vue 创建一个前端应用程序,包括注册和登录页面,并使用 Axios 库与 Django API 进行通信。 5. 使用 Vuex 来管理用户状态,并使用路由守卫来保护需要登录才能访问的页面。 6. 完成登录注册功能的测试。 这是一个大致的流程,希望这能帮到你。如果你还有任何疑问,欢迎提出。 ### 回答2: 好的,我可以为您提供一个基于Django和Vue的登录注册项目。 首先,我们需要创建一个Django项目。打开命令行,在您的工作目录下运行以下命令: ``` django-admin startproject login_project ``` 进入`login_project`文件夹,创建一个Django应用程序: ``` cd login_project django-admin startapp login_app ``` 在`settings.py`文件中,将应用程序添加到`INSTALLED_APPS`列表中: ```python INSTALLED_APPS = [ ... 'login_app', ] ``` 接下来,我们需要创建用于用户认证的模型。在`models.py`文件中,添加以下代码: ```python from django.db import models from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin class UserManager(BaseUserManager): def create_user(self, email, password=None, **extra_fields): if not email: raise ValueError('Email address is required') email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) return self.create_user(email, password=password, **extra_fields) class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True) username = models.CharField(max_length=255) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] def __str__(self): return self.email ``` 运行数据库迁移以创建表: ``` python manage.py makemigrations python manage.py migrate ``` 接下来,我们需要创建登录和注册的视图。在`views.py`文件中,添加以下代码: ```python from django.contrib.auth import authenticate, login, logout from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from .models import User @csrf_exempt def register(request): if request.method == 'POST': email = request.POST.get('email') password = request.POST.get('password') username = request.POST.get('username') user = User.objects.create_user(email=email, password=password, username=username) login(request, user) return JsonResponse({'message': '注册成功!'}) else: return JsonResponse({'message': '请求方法不正确'}) @csrf_exempt def login_view(request): if request.method == 'POST': email = request.POST.get('email') password = request.POST.get('password') user = authenticate(request, email=email, password=password) if user is not None: login(request, user) return JsonResponse({'message': '登录成功!'}) else: return JsonResponse({'message': '用户名或密码不正确'}) else: return JsonResponse({'message': '请求方法不正确'}) def logout_view(request): logout(request) return JsonResponse({'message': '已退出登录'}) ``` 为了使视图可用,我们还需要创建URL模式。在`urls.py`文件中,添加以下代码: ```python from django.urls import path from . import views urlpatterns = [ path('register/', views.register, name='register'), path('login/', views.login_view, name='login'), path('logout/', views.logout_view, name='logout'), ] ``` 现在,我们已经完成了Django的部分。接下来,我们将通过安装Vue CLI并创建一个Vue项目来完成前端部分。 首先安装Vue CLI。打开命令行并运行以下命令: ``` npm install -g @vue/cli ``` 通过运行以下命令,在您的工作目录中创建Vue项目: ``` vue create login_vue ``` 选择Manually select features,并确保选择Router和Vuex进行安装。 接下来,我们需要在Vue项目中创建一个登录和注册的组件。我们可以在`views`文件夹中创建`Login.vue`和`Register.vue`组件。 在`Login.vue`组件中,我们可以添加以下代码: ```html <template> <div> <h1>Login</h1> <form @submit="login"> <input type="email" v-model="email" placeholder="Email" required><br> <input type="password" v-model="password" placeholder="Password" required><br> <button type="submit">Login</button> </form> </div> </template> <script> export default { data() { return { email: '', password: '' } }, methods: { login(event) { event.preventDefault() // 在这里发送登录请求 } } } </script> ``` 在`Register.vue`组件中,我们可以添加以下代码: ```html <template> <div> <h1>Register</h1> <form @submit="register"> <input type="email" v-model="email" placeholder="Email" required><br> <input type="password" v-model="password" placeholder="Password" required><br> <input type="text" v-model="username" placeholder="Username" required><br> <button type="submit">Register</button> </form> </div> </template> <script> export default { data() { return { email: '', password: '', username: '' } }, methods: { register(event) { event.preventDefault() // 在这里发送注册请求 } } } </script> ``` 接下来,我们将创建一个路由以管理登录和注册的页面。在项目的`router.js`文件中,添加以下代码: ```javascript import Vue from 'vue' import VueRouter from 'vue-router' import Login from './views/Login.vue' import Register from './views/Register.vue' Vue.use(VueRouter) const routes = [ { path: '/login', component: Login }, { path: '/register', component: Register } ] const router = new VueRouter({ routes }) export default router ``` 最后,我们需要在Vue项目的入口文件`main.js`中导入路由: ```javascript import Vue from 'vue' import App from './App.vue' import router from './router' Vue.config.productionTip = false new Vue({ router, render: h => h(App), }).$mount('#app') ``` 现在,我们已经完成了Django和Vue的登录注册项目。通过将两者结合起来,您可以在前端构建用户界面,将用户数据发送到Django后端进行验证和存储。 希望以上内容对您有所帮助!如果您有任何其他问题,请随时提问。 ### 回答3: 当然,下面我来为您介绍一下如何使用Django和Vue.js来完成登录和注册的项目。 1. 首先,您需要安装Django和Vue.js。可以使用pip来安装Django,使用npm来安装Vue.js。 2. 创建Django项目。在终端中运行以下命令: ``` django-admin startproject projectname cd projectname ``` 3. 创建Django应用程序。在终端中运行以下命令: ``` python manage.py startapp appname ``` 4. 在Django的app目录中创建模型。打开`models.py`文件,定义用户模型,包括用户名、密码等字段。 5. 迁移数据库。在终端中运行以下命令: ``` python manage.py makemigrations python manage.py migrate ``` 6. 在Django的app目录中创建视图。打开`views.py`文件,编写处理登录和注册请求的视图函数。 7. 在Django的app目录中创建URL。打开`urls.py`文件,将URL与视图函数进行绑定。 8. 创建Vue.js项目。在终端中运行以下命令: ``` vue create projectname cd projectname ``` 9. 在Vue.js项目中配置路由。打开`router/index.js`文件,为登录和注册页面配置路由。 10. 创建登录和注册组件。在Vue.js项目的`src/components`目录中创建登录和注册的组件,并编写相应的HTML和JavaScript代码。 11. 在组件中使用Axios库发送异步请求。在登录和注册组件中,使用Axios来发送请求到Django后端,获取用户输入的用户名和密码,并将其发送给后台进行验证。 12. 处理后端验证。在Django的视图函数中,接收并验证用户发送的请求,检查用户名和密码是否匹配。 13. 返回响应。在Django的视图函数中,根据验证的结果,返回相应的响应给前端。 14. 在Vue.js组件中根据后端返回的响应进行相应的处理。例如,如果登录或注册成功,可以跳转到用户的首页;如果失败,可以显示错误消息。 以上就是使用Django和Vue.js完成登录和注册项目的基本步骤。您可以根据具体的需求进行适当的调整和扩展,以满足您的实际需求。如果您需要更详细的代码示例和详细步骤,请告诉我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值