目录

  • 可重用注册登录系统
    • 项目开始前的思考
    • 搭建项目环境
    • 设计数据库模型
      • 数据库模型文件
      • 设置数据库后端
      • 注册app
      • 生成迁移脚本并写入数据库
      • 测试是否成功
      • 数据库模型后台管理
    • 路由与视图函数框架构建
    • 路由配置
      • 视图函数的配置
      • 模板template的配置
      • 测试是否成功
    • 前端页面设计与优化
    • 完善登录的视图函数
    • session会话与登录的视图函数
    • 图片验证码
      • Django表单
    • 创建表单模型
    • 视图逻辑化
    • Template页面优化
      • 验证是否正确
    • 邮箱注册
      • 发送邮件功能测试
      • 基本的注册功能实现
        • 注册表单
        • 实现注册视图
        • Template模板的更改
      • 注册添加密码加密功能
      • 邮件注册确认
        • 创建模型
        • 修改视图
        • 处理邮件确认请求
        • 修改登录规则
    • 其他

可重用注册登录系统

  • 注册(邮箱注册,手机,微信,QQ)
  • 登录
  • 注销

项目开始前的思考

  • 路由配置

    urlpattern = [path('/register/', views.register), path('/login/', views.login), path('/logout/', views.logout),
    ]
    
  • 视图配置(重点)----

  • 数据库模型Model:

    class User:id, name, password, email, create_time, update_timelast_time(最后一次登录的时间), gender, province
    
  • 模板Template: register.html, login.html, index.html

搭建项目环境

  • 创建Django项目

  • 创建app

    $ python manage.py startapp login
    
  • 设置时区和语言

    # filename: loginRegister/settings.py
    # LANGUAGE_CODE = 'en-us'
    LANGUAGE_CODE = 'zh-hans'# TIME_ZONE = 'UTC'
    TIME_ZONE = 'Asia/Shanghai'
    
  • 数据库表生成

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

    $  python manage.py runserver 9999
    
  • 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时为添加时的时间,更新对象时不会有变动。
  • 修改时间(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.nameclass Meta:verbose_name = " 网 站 用 户 管 理 "verbose_name_plural = verbose_name

设置数据库后端

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

注册app

# loginRegister/settings.pyINSTALLED_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.pyfrom django.contrib import admin# Register your models here.
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 = 10admin.site.register(SiteUser, SiteUserAdmin)

浏览器访问,检测是否成功?(完美搞定)

  • 访问网址: http://127.0.0.1:9999/adm

路由与视图函数框架构建

路由设计:

URL 视图views 模板 功能
/index/ login.views.index index.html 首页
/login/ login.views.login login.html 登录页面
/register/ login.views.register register.html 注册界面
/logout/ login.views.logout 无需返回页面 登出界面

访问策略:

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

路由配置

  • 主路由配置文件
#loginRegister/urls.py
from django.contrib import admin
from django.urls import path,includeurlpatterns = [path('admin/', admin.site.urls),path('', include('login.urls')),
]
  • 子路由配置文件(login子应用的)
#login/urls.py
from  django.urls import path, include
from login import viewsurlpatterns = [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):passreturn render(request,'login/index.html')
def  login(request):passreturn render(request,'login/login.html')def  register(request):passreturn render(request,'login/register.html')
def  logout(request):passreturn  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/


简易的设计页面已经完成

结合git,每次做完文件更改的时候,提交、

前端页面设计与优化

我们有现成的开源前端CSS框架!Bootstrap4就是最好的css框架之一

官方文档

Bootstrap核心:
Bootstrap入门模板
Bootstrap栅格系统
Boostrap表单组件
Bootstrap警告框

完善登录的视图函数

  • html和视图函数交互的完善

    • 修改1. 有message信息则显示, 没有就不显示。
    • 修改2: 提交登录信息时, 以post方法提交给/login/对应的是视图函数处理。
    • 修改3: Django提供了csrf防攻击的机制, 添加该信息则可顺利访问登陆界面
    • 修改4:name="username"指定表单内容存储的key值名称, eg: {“username”:“你填的用户名”,“password”:“你填的密码” }
      将页面完善,更改html文件,
#template/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>
#template/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>#修改1。有message信息则显示,,没有则不显示{% if message %}<div class="alert alert-warning" role="alert"><strong>登录失败!</strong> {{ message }}</div>{% endif %}# 修改2: 提交登录信息时, 以post方法提交给/login/对应的是视图函数处理。<form action="/login/" method="post"># 修改3: Django提供了csrf防攻击的机制, 添加该信息则可顺利访问登陆界面{% csrf_token %}<div class="form-group"><label>用户名</label># 修改4:name="username"指定表单内容存储的key值名称, eg:{"username":"你填的用户名"}<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>
#template/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>
  • 视图函数的完善
#login/views
from django.shortcuts import render,redirect# Create your views here.
from login.models import SiteUser
# Create your views here.def index(request):passreturn 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):passreturn render(request, 'login/register.html')def logout(request):pass#redirect:重定向(跳转)return redirect('/login/')
  • 浏览器访问


session会话与登录的视图函数

  • 登录成功, 存储登录的用户信息到session中

  • 在首页添加登出的超链接并测试


#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>
  • 登录成功, 存储登录的用户信息到session中
  • 登出时,清空session信息
#login/views.py
from django.shortcuts import render, redirect# Create your views here.
from login.models import SiteUserdef index(request):passreturn 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'] = Truerequest.session['user_id'] = user.idrequest.session['username'] = user.namereturn  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):passreturn 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/')
  • 浏览器访问,检测是否成功?

图片验证码

为了防止机器人频繁登录网站或者破坏分子恶意登录,很多用户登录和注册系统都提供了图形验证码功能。

在Django中实现图片验证码功能非常简单,有现成的第三方库可以使用,我们不必自己开发(不必重复造轮子)。这个库叫做django-simple-captcha。
)

Django表单

我们前面都是手工在HTML文件中编写表单form元素,然后在views.py的视图函数中接收表单中的用户数据,再编写验证代码进行验证,最后使用ORM进行数据库的增删改查。这样费时费力,整个过程比较复杂,而且有可能写得不太恰当,数据验证也比较麻烦。设想一下,如果我们的表单拥有几十上百个数据字段,有不同的数据特点,如果也使用手工的方式,其效率和正确性都将无法得到保障。有鉴于此,Django在内部集成了一个表单功能,以面向对象的方式,直接使用Python代码生成HTML表单代码,专门帮助我们快速处理表单相关的内容。

Django的表单给我们提供了下面三个主要功能:

  • 准备和重构数据用于页面渲染;
  • 为数据创建HTML表单元素;
  • 接收和处理用户从表单发送过来的数据。

编写Django的form表单,非常类似我们在模型系统里编写一个模型。在模型中,一个字段代表数据表的一列,而form表单中的一个字段代表<form>中的一个<input>元素。

戳我了解更多Django表单操作

Django表单使用指南

创建表单模型

# /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="验证码")

视图逻辑化

from login.forms import  LoginForm
# login/views.py
def login(request):# 请求方法为POST提交if request.method == 'POST':# 修改1: 实例化表单对象login_form = LoginForm(request.POST)# 修改2: 验证表单数据的合法性if login_form.is_valid():# 修改3:获取表单填写的数据,数据清洗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'] = Truerequest.session['user_id'] = user.idrequest.session['username'] = user.namereturn  redirect('/index/')else:message = "用户名或者密码错误"# 修改4: locals()以字典方式返回当前所有的变量# eg:{'message':'xxxx', 'login_form':'xxx'}return  render(request, 'login/login.html', locals())else:message = "填写的登录信息不合法"return render(request, 'login/login.html', locals())# 请求方法是GET请求login_form = LoginForm()return render(request, 'login/login.html', locals())

Template页面优化

# templates/login/login.html(部分修改)<h3 style="text-align: center">用户登录</h3>
# 修改1: 不同的报错,提示不同的信息
{% 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 %}<div class="form-group"># 修改2:<label>{{ login_form.username.label }}</label><input type="text" class="form-control" name="username">
</div>
<div class="form-group"># 修改3:<label>{{ login_form.password.label }}</label><input type="password" class="form-control" name="password"><small class="form-text text-muted">密码必须是字母、数字或者特殊符号组成.</small>
</div># 修改4: 最重要的,添加验证码表单
<div class="form-group"><label>{{ login_form.captcha.label }}</label>{{ login_form.captcha }}
</div>

验证是否正确

邮箱注册

发送邮件功能测试

  • 配置邮件信息

    # loginRegister/settings.py# mail configure(添加信息如下)
    EMAIL_HOST = 'smtp.163.com'  # 'smtp.qq.com'
    EMAIL_PORT = 25
    EMAIL_HOST_USER = 'Xx@163.com   # 你的邮箱地址
    EMAIL_HOST_PASSWORD = 'XXXXXXXXX'   # 不是邮箱的登录密码,而是授权码(如何获取授权码)
    EMAIL_USE_SSL = False                     # 不开启ssl
    
  • 如何获取授权码?


在开启smtp服务的时候,需要扫码,发送短信之后就可以获得授权码

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

    Terminal输入命令> python manage.py shell
    In [1]: from django.core.mail import send_mailIn [2]: from loginRegister.settings import EMAIL_HOST_USERIn [3]: send_mail("测试邮件", "content", EMAIL_HOST_USER, ['XXXX@163.com'])
  • 验证是否成功? 查看是否受到邮件?

基本的注册功能实现

注册表单
# login/forms.py
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='验证码')
实现注册视图
  • 如果用户已经登录,则不能注册跳转到首页。
  • 如果是GET请求,返回用户注册的html页面。
  • 如果是POST请求, 先验证提交的数据是否通过,清洗数据。 接下来判断用户名和邮箱是否已经被注册, 将注册的信息存储到数据库,跳转到登录界面。
  • 额外功能: 为了数据的安全性注册时,密码存储到数据库不是明文存储,而是先加密再存储。

view的逻辑有点问题

# login/views.py
from django.shortcuts import render, redirect# Create your views here.
from login.models import SiteUser
from login.forms import  LoginForm,RegisterFormdef 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())
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>>

注册添加密码加密功能

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

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

    import hashlib
    def hash_code(s, salt='mysite'):# 加点盐h = hashlib.sha256()s += salth.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.pyclass SiteUser(models.Model):# .......has_confirmed = models.BooleanField(default=False, 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.codeclass Meta:ordering = ["-create_time"]verbose_name = "确认码"verbose_name_plural = "确认码"

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

python manage.py makemigrations
python manage.py migrate

顺便修改一下admin.py文件,方便我们在后台修改和观察数据

# login/admin.py
from login.models import SiteUser,ConfirmString
admin.site.register(ConfirmString)
修改视图
def register(request):# ................code = make_confirm_string(new_user)send_email(email, code)message = '请前往邮箱进行确认!'# ..................

make_confirm_string()是创建确认码对象的方法,代码如下:

import datetimedef make_confirm_string(user):now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")code = hash_code(user.name, now)models.ConfirmString.objects.create(code=code, user=user,)return code

send_email(email, code)方法接收两个参数,分别是注册的邮箱和前面生成的哈希值,代码如下:

#login/utils.py
def send_email(email, code):print('send mail.........')subject = '注册确认邮件'text_content = '''感谢注册,这里是登录注册系统网站!\如果你看到这条消息,说明你的邮箱服务器不提供HTML链接功能,请联系管理员!'''html_content = '''<p>感谢注册<a href="http://{}/confirm/?code={}" target=blank>点击验证</a>,\这里是登录注册系统网站!</p><p>请点击站点链接完成注册确认!</p><p>此链接有效期为{}天!</p>'''.format('127.0.0.1:9999', code, settings.CONFIRM_DAYS)send_mail(subject, text_content,settings.EMAIL_HOST_USER, [email, ], html_message=html_content)

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

# 注册有效期天数
CONFIRM_DAYS = 3

测试:注册一个用户,判断是否能收到确认邮件。

跳过上文测试,直接处理邮件确认请求

处理邮件确认请求

在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_timenow = 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.is_confirmed = Trueconfirm.user.save()confirm.delete()message = '感谢确认,请使用账户登录!'return render(request, 'login/confirm.html', locals())

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

页面中通过JS代码,设置2秒后自动跳转到登录页面,可根据自己的需要去除或者美化。

<h1 style="margin-left: 100px;">{{ message }}</h1><script>
window.setTimeout("window.location='/login/'",2000);
</script>
修改登录规则

既然未进行邮件确认的用户不能登录,那么我们就必须修改登录规则,如下所示:

#login/utils
if not user.has_confirmed:message = '该用户还未经过邮件确认!'return render(request, 'login/login.html', locals())

在注册完成之后测试

其他

  • 如何在windows安装redis? 点击进入

  • 理解Celery工作原理点击进入

    (实现异步任务和定时任务)

django完成一个可重用注册登录系统相关推荐

  1. python学习第八天---用Django框架创建可重用注册登录系统

    python学习第八天---用Django框架创建可重用注册登录系统 实现的功能 项目开始前的整体规划 搭建环境完成基础配置 创建app 更改语言和时区 数据库表生成 启动开发服务器 浏览器访问,检测 ...

  2. Django 可重用注册登录系统

    文章目录 一.可重用注册登录系统 1.项目开始前的思考 2.搭建项目环境 3.设计数据库模型 1)数据库模型文件 2)设置数据库后端 3)注册app 4)生成迁移脚本并写入数据库 5)测试是否成功 6 ...

  3. 用Python基础创建一个简单的注册登录系统

    在学完Python基础后,是不是有一点想法去做一点好玩的程序呢?如果想可以看看这个注册登录系统,会带给你一些思路. 大家都对登录注册系统司空见惯了吧,我们周围的许多东西都需要登录注册系统,例如很受大众 ...

  4. Python(18)——Django实战1之可重用注册登录系统(从面到点剖析)

    文章目录 前言 0.项目开始前的思考 1.搭建项目环境(和上一篇文章一样) 1.1 创建Django项目 1.2 创建app 1.3 设置时区(中文显示) 1.4 数据库表生成 1.5 启动开发服务器 ...

  5. python注册系统_Python制作简易注册登录系统

    Python制作简易注册登录系统 这篇文章主要为大家详细介绍了 Python 简易注册登录系统的制作方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 Python 是一种面向对象.解释型计算机程 ...

  6. php写的注册登录系统吗,php注册登录系统简化版_php技巧

    登录注册系统是日常上网最普通的操作,我设了一个分类一步步完善注册登录系统,若哪里有误,请见谅. 所用语言:php 数据库 :mysql 本次实现功能: 1.用户注册 2.用户登录 主要文件: 完整代码 ...

  7. PHP注册登录系统(一)-极简

    按: 所用语言:PHP 数据库 :MySQL // 创建数据库test create database test; // 创建数据表 create table user(id int(10) not ...

  8. 移动APP整体策划-004-App注册登录系统策划方案

    注册登录系统 注册登录系统,是app最基础的系统模块之一.账号id是用户的唯一标识,基于这个账号记录用户行为,为用户提供各种各样的个性化服务.没有这个账号系统,后面的一切都是空话.当然,如果你是做一个 ...

  9. 注册登录系统(含MD5加密,注册、登录、推出、注销账号)

    不废话,直接干 用户管理系统-登录(Login)篇(含MD5加密) 要引用的jar包有mysql-connector-java-5.1.44-bin.jar和log4j-1.2.15.jar(都可以在 ...

最新文章

  1. 就是一个斜杠的事情!
  2. mysql多表查询插入更新_Mysql多表查询,多表插入和多表更新
  3. CodeForces-1058B B. Vasya and Cornfield
  4. RNA-seq最强综述名词解释思维导图|关于RNA-seq,你想知道的都在这(续)
  5. mui 头部tab代码2
  6. Spring cloud eureka 入门使用及指导说明(单机篇)
  7. Python3之Django框架搭建详细步骤
  8. html浮动之后怎么隐藏,div浮动之后排在一行,在把浮动去掉,把div用display设置成inline-block之后就不能排在一行了。...
  9. 小米兰亭pro ttf_小米10Pro使用体验(三)
  10. 什么是蜘蛛池?有什么作用?
  11. 为了找出羞羞视频,百度云居然有“娇喘模式”
  12. excel条形图-蝴蝶图的画法
  13. 30分钟LINQ教程(转)
  14. 个人计算机视觉学习路线
  15. 经典非局部均值滤波(NLM)算法python实现(2)
  16. VR全景制作的展示方式你了解多少?具体有哪些?
  17. Elasticsearch数据读写过程
  18. 信息学奥赛一本通——2068:【例2.6】鸡兔同笼
  19. 自学软件测试真的可以吗?
  20. RocketMQ (六) 主题-Topic

热门文章

  1. 2021年上半年软考真题数据库系统工程师真题
  2. 微信公众平台数据统计功能的作用是什么?
  3. 通过位与方法获取三色值,十六进制色值转换RGB
  4. android 记录打印文件
  5. 录音实时转写软件哪个好?这三个软件帮你搞定录音如何转文字
  6. 谷歌(Chrome)浏览器丨插件安装教程
  7. Hark的数据结构与算法练习之冒泡排序
  8. src 漏洞平台 应急响应中心 提交漏洞 简介
  9. 管理人员巡店用表-店长每日工作流程
  10. 给电脑文件批量重命名和更改后缀名