快捷搜索:
来自 计算机编程 2019-11-10 08:01 的文章
当前位置: 67677新澳门手机版 > 计算机编程 > 正文

Django客商登录与注册系统

生龙活虎、创立项目

1.1.开立项目和app

django-admin startproject mysite_login

python manage.py startapp login

1.2.安装时区和语言

Django私下认可使用美利哥时刻和菲律宾语,在项指标settings文件中,如下所示:

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

我们把它改为亚洲/上海岁月和国文

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

1.3.启动

运作测量检验一下工程,在本机的浏览器中拜访http://127.0.0.1:8000/

图片 1

 二、设计数据模型

 2.1.数据库模型设计

 作为四个顾客登入和登记类型,须求保留的都以种种用户的相干音讯。很确定,我们至少需要一张顾客表User,在客户表里须求保留上边包车型大巴信息:

  • 用户名
  • 密码
  • 邮箱地址
  • 性别
  • 开创时间

 步入login/models.py,代码如下

# login/models.py

from django.db import models


class User(models.Model):
    '''用户表'''

    gender = (
        ('male','男'),
        ('female','女'),
    )

    name = models.CharField(max_length=128,unique=True)
    password = models.CharField(max_length=256)
    email = models.EmailField(unique=True)
    sex = models.CharField(max_length=32,choices=gender,default='男')
    c_time = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['c_time']
        verbose_name = '用户'
        verbose_name_plural = '用户'

各字段含义:

  • name必填,最长不超过1二十二个字符,並且唯生龙活虎,也正是不能够有意气风发致姓名;
  • password必填,最长不当先2陆拾三个字符(实际大概无需如此长卡塔尔国;
  • email使用Django内置的邮箱类型,何况唯大器晚成;
  • 性别使用了贰个choice,只可以选拔男照旧女,默以为男;
  • 使用__str__辅助人性化展现对象消息;
  • 元数据里定义客户按创制时间的反序排列,也正是多年来的首先展现;

专一:这里的客户名指的是网络上注册的顾客名,不要等同于现实中的真实姓名,所以利用了独一机制。借使是实际中得以另行的人名,那一定是无法安装unique的。

 2.2.安装数据库为Mysql

在settings.py修改

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django',        #数据库名字
        'USER': 'root',          #账号
        'PASSWORD': '123456',      #密码
        'HOST': '127.0.0.1',    #IP
        'PORT': '3306',                   #端口
    }
}

init.py里面导入pymysql模块

# login/init.py

import pymysql
pymysql.install_as_MySQLdb()

  2.3.数据库迁移

注册app

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

搬迁到数据库

python manage.py makemigrations

python manage.py migrate

三、admin后台

3.1.在admin中登记模型

# login/admin.py

from django.contrib import admin
from . import models

admin.site.register(models.User)

 3.2.成立顶尖管理员

python manage.py createsuperuser

接下来再充实多少个测验客户

 

图片 2

 

 四、url路由和视图

 前面大家早就创办好数据模型了,並且在admin后新北增加了有的测验客商。上边大家就要统筹好站点的url路由、对应的拍卖视图函数以致接收的前端模板了。

 4.1.路由规划

起首设想供给下边包车型大巴八个U帕杰罗L:

 图片 3

设想到登陆种类归属站点的一流功用,为了直观和更便于接纳,这里未有使用二级路由的格局,而是在根路由下间接编写路由条约,同样也从未接纳反向深入解析名(name参数卡塔尔。

# mysite_login/urls.py

from django.conf.urls import url
from django.contrib import admin
from login import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
    url(r'^login/', views.login),
    url(r'^register/', views.register),
    url(r'^logout/', views.logout),
]

4.2.架构最早视图

路由写好了,就进来login/views.py文件编写视图的框架,代码如下:

# login/views.py

from django.shortcuts import render,redirect

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
    return redirect('/index/')

小编们先不发急达成视图内部的现实细节,而是把框架先搭建起来。

4.3.成立HTML页面文件

在类型根路线的login目录中创建二个templates目录,再在templates目录里成立叁个login目录

login/templates/login目录中开创多个文件index.htmllogin.html以及register.html ,并写入如下的代码:

index.html

{#login/templates/login/index.html#}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>

login.html

{#login/templates/login/login.html#}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h1>登录页面</h1>
</body>
</html>

register.html

{#login/templates/login/register.html#}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
<h1>注册页面</h1>
</body>
</html>

 五、前端页面设计

 5.1.原生HTML页面

login.html文件中的内容,写入下边包车型大巴代码:

{#login/templates/login/login.html#}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
     <div style="margin: 15% 40%;">
        <h1>欢迎登录!</h1>
       <form action="/login/" method="post">
            <p>
                <label for="id_username">用户名:</label>
                <input type="text" id="id_username" name="username" placeholder="用户名" autofocus required />
            </p>

            <p>
                <label for="id_password">密码:</label>
                <input type="password" id="id_password" placeholder="密码" name="password" required >
            </p>
            <input type="submit" value="确定">
        </form>
    </div>



</body>
</html>

可以看来如下图的页面:

图片 4

5.2.引入Bootstrap

Bootstrap3.3.7下载地址

根目录下新建三个static目录,并将解压后的bootstrap-3.3.7-dist目录,全体拷贝到static目录中,如下图所示:

 图片 5

是因为Bootstrap正视JQuery,所以大家须要提前下载并引进JQuery:下载地址

在static目录下,新建三个css和js目录,作为以后的体裁文件和js文件的寄存地,将大家的jquery文件拷贝到static/js目录下。

 图片 6

下一场张开项目标settings文件,在最上面增加配置,用于内定静态文件的查找目录:

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

5.3.创建base.html模板

既然要将前端页面做得像个标准,那么就不能够和前面同样,各样页面都各写各的,单打独隔山观虎斗。叁个网址有自个儿的集结风格和公用部分,可以把那部分内容集中到二个底工模板base.html中。现在,在根目录下的templates中新建二个base.html文本用作站点的功底模板。

在Bootstrap文书档案中,为我们提供了二个非常简单而又实用的宗旨模板,代码如下:

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
    <link href="css/bootstrap.min.css" rel="stylesheet">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="http://www.k-haruka-m.com/uploads/allimg/191110/0P12L494-6.jpg"></script>
      <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <h1>你好,世界!</h1>

    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="http://www.k-haruka-m.com/uploads/allimg/191110/0P12L4W-8.jpg"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="js/bootstrap.min.js"></script>
  </body>
</html>

将它完全拷贝到base.html文件中。

 5.4.创设页面导航条

Bootstrap提供了现存的导航条组件

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        Toggle navigation



      </button>
      <a class="navbar-brand" href="#">Brand</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">Link (current)</a></li>
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown </a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <form class="navbar-form navbar-left">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
      <ul class="nav navbar-nav navbar-right">
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown </a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
          </ul>
        </li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>

图片 7

里头有局地有的,譬如寻觅框是咱们当前还无需的,须要将剩余的内容裁剪掉。同有时候,有部分名称和url地址等急需按大家的其实内容纠正。最后导航条的代码如下:

<nav class="navbar navbar-default">
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#my-nav" aria-expanded="false">
            切换导航条



          </button>
          <a class="navbar-brand" href="#">Mysite</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="my-nav">
          <ul class="nav navbar-nav">
            <li class="active"><a href="/index/">主页</a></li>
          </ul>
          <ul class="nav navbar-nav navbar-right">
            <li><a href="/login/">登录</a></li>
            <li><a href="/register/">注册</a></li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>

5.5.用到Bootstrap静态文件

{% static '相对路径' %}本条Django为大家提供的静态文件加载方法,能够将页面与静态文件链接起来

 最后,base.html内容如下:

{% load staticfiles %}

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>{% block title %}base{% endblock %}</title>

    <!-- Bootstrap -->
    <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="http://www.k-haruka-m.com/uploads/allimg/191110/0P12L494-6.jpg"></script>
      <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
    {% block css %}{% endblock %}
  </head>
  <body>
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#my-nav" aria-expanded="false">
            切换导航条



          </button>
          <a class="navbar-brand" href="#">Mysite</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="my-nav">
          <ul class="nav navbar-nav">
            <li class="active"><a href="/index/">主页</a></li>
          </ul>
          <ul class="nav navbar-nav navbar-right">
            <li><a href="/login/">登录</a></li>
            <li><a href="/register/">注册</a></li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>

    {% block content %}{% endblock %}


    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="{% static 'js/jquery-3.2.1.js' %}"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
  </body>
</html>

简言之说明:

  • 透过页面最上部的{% load staticfiles %}加载后,才得以利用static方法;
  • 通过{% block title %}base{% endblock %},设置了叁个动态的页面title块;
  • 通过{% block css %}{% endblock %},设置了一个动态的css加载块;
  • 通过{% block content %}{% endblock %},为实际页面包车型地铁重心内容留下接口;
  • 通过{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}将样式文件指向了大家的骨子里静态文件,下边包车型客车js脚本也是均等的道理。

 看下效果

图片 8

5.6.企划登入页面

Bootstarp提供了壹当中央的表单样式,代码如下:

<form>
  <div class="form-group">
    <label for="exampleInputEmail1">Email address</label>
    <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Email">
  </div>
  <div class="form-group">
    <label for="exampleInputPassword1">Password</label>
    <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
  </div>
  <div class="form-group">
    <label for="exampleInputFile">File input</label>
    <input type="file" id="exampleInputFile">
    <p class="help-block">Example block-level help text here.</p>
  </div>
  <div class="checkbox">
    <label>
      <input type="checkbox"> Check me out
    </label>
  </div>
  <button type="submit" class="btn btn-default">Submit</button>
</form>

如下:

图片 9

我们构成Bootstrap和日前自个儿写的form表单,订正login/templates/login/login.html成相符项目必要的旗帜:

{% extends 'login/base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}
    <link rel="stylesheet" href="{% static 'css/login.css' %}">
{% endblock %}


{% block content %}
    <div class="container">
        <div class="col-md-4 col-md-offset-4">
          <form class='form-login' action="/login/" method="post">
              <h2 class="text-center">欢迎登录</h2>
              <div class="form-group">
                <label for="id_username">用户名:</label>
                <input type="text" name='username' class="form-control" id="id_username" placeholder="Username" autofocus required>
              </div>
              <div class="form-group">
                <label for="id_password">密码:</label>
                <input type="password" name='password' class="form-control" id="id_password" placeholder="Password" required>
              </div>
              <button type="reset" class="btn btn-default pull-left">重置</button>
              <button type="submit" class="btn btn-primary pull-right">提交</button>
          </form>
        </div>
    </div> <!-- /container -->
{% endblock %}

说明:

  • 通过{% extends 'base.html' %}三番八回了‘base.html’模板的剧情;
  • 通过{% block title %}登录{% endblock %}设置了特别的title;
  • 通过block css引进了指向性的login.css体制文件;
  • 重视内容定义在block content内部
  • 增添了多少个重新设置开关。

static/css目录中新建二个login.css体制文件,这里大约地写了点样式,

body {
  background-color: #eee;
}
.form-login {
  max-width: 330px;
  padding: 15px;
  margin: 0 auto;
}
.form-login .form-control {
  position: relative;
  height: auto;
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
  padding: 10px;
  font-size: 16px;
}
.form-login .form-control:focus {
  z-index: 2;
}
.form-login input[type="text"] {
  margin-bottom: -1px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.form-login input[type="password"] {
  margin-bottom: 10px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

末段效果

图片 10

 六、登陆视图

6.1.登入视图

基于我们在路由中的设计,顾客通过login.html中的表单填写客商名和密码,并以POST的方法发送到服务器的/login/位置。服务器通过login/views.py中的login()视图函数,选择并拍卖这一呼吁。

作者们能够透过上边的方法接受和处理乞求:

def login(request):
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')        return redirect('/index/')
    return render(request, 'login/login.html')

还须要在前面一个页面包车型地铁form表单内增加四个{% csrf_token %}标签:

<form class='form-login' action="/login/" method="post">
  {% csrf_token %}
  <h2 class="text-center">欢迎登录</h2>
  <div class="form-group">
  ......
</form>

进去登陆页面,输入顾客名,密码然后跳转到index页面。

6.2.数量表明

经过唯风度翩翩的客商名,使用Django的ORM去数据库中询问客户数据,假诺有相配项,则打开密码相比,若无相配项,表达客户名官样文章。若是密码比较错误,表明密码不正确。

def login(request):
    if request.method == "POST":
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        if username and password:  # 确保用户名和密码都不为空
            username = username.strip()
            # 用户名字符合法性验证
            # 密码长度验证
            # 更多的其它验证.....
            try:
                user = models.User.objects.get(name=username)
            except:
                return render(request, 'login/login.html')
            if user.password == password:
                return redirect('/index/')
    return render(request, 'login/login.html')

6.3.增多提醒消息

地点的代码还缺少相当重要的风度翩翩部分剧情,提醒音信!无论是登录成功或然败北,客商都尚未获得别的提示音信,那明显是十一分的。

改过一下login视图:

def login(request):
    if request.method == "POST":
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        message = "所有字段都必须填写!"
        if username and password:  # 确保用户名和密码都不为空
            username = username.strip()
            # 用户名字符合法性验证
            # 密码长度验证
            # 更多的其它验证.....
            try:
                user = models.User.objects.get(name=username)
                if user.password == password:
                    return redirect('/index/')
                else:
                    message = "密码不正确!"
            except:
                message = "用户名不存在!"
        return render(request, 'login/login.html', {"message": message})
    return render(request, 'login/login.html')

追加了message变量,用于保存提示音讯。当有错误新闻的时候,将错误音信打包成多个字典,然后作为第七个参数提供给render()方法。这几个数据字典在渲染模板的时候会传递到模板里供您调用。

为了在前端页面彰显消息,还须要对login.html开展纠正:

{% extends 'login/base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}
    <link rel="stylesheet" href="{% static 'css/login.css' %}">
{% endblock %}


{% block content %}
    <div class="container">
        <div class="col-md-4 col-md-offset-4">
            <form class='form-login' action="/login/" method="post">

                {% if message %}
                    <div class="alert alert-warning">{{ message }}</div>
                {% endif %}

                {% csrf_token %}
                <h2 class="text-center">欢迎登录</h2>
                <div class="form-group">
                    <label for="id_username">用户名:</label>
                    <input type="text" name='username' class="form-control" id="id_username" placeholder="Username"
                           autofocus required>
                </div>
                <div class="form-group">
                    <label for="id_password">密码:</label>
                    <input type="password" name='password' class="form-control" id="id_password" placeholder="Password"
                           required>
                </div>
                <button type="reset" class="btn btn-default pull-left">重置</button>
                <button type="submit" class="btn btn-primary pull-right">提交</button>
            </form>
        </div>
    </div> <!-- /container -->
{% endblock %}

index.html主页模板也改进一下,删除原有内容,加多底下的代码:

{#login/templates/login/index.html#}

{% extends 'login/base.html' %}
{% block title %}主页{% endblock %}
{% block content %}
    <h1>欢迎回来!</h1>
{% endblock %}

 七、Django表单

Django的表单给大家提供了下边多少个重大功能:

  • 未雨策动和重构数据用于页面渲染;
  • 为数量创制HTML表单成分;
  • 收下和拍卖客户从表单发送过来的数码

 7.1.创设表单模型

from django import forms


class UserForm(forms.Form):
    username = forms.CharField(label="用户名", max_length=128)
    password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput)

说明:

  • 要先河入forms模块
  • 具有的表单类都要持续forms.Form类
  • 种种表单字段都有友好的字段类型例如CharField,它们分别对应风度翩翩种HTML语言中<form>内的一个input成分。那或多或少和Django模型系统的规划相当帅似。
  • label参数用于安装<label>标签
  • max_length界定字段输入的最大尺寸。它同临时间起到四个功用,一是在浏览器页面节制客户输入不可超过字符数,二是在后端服务器验证客户输入的尺寸也不可超过。
  • widget=forms.PasswordInput用以钦命该字段在form表单里突显为<input type='password' />,也正是密码输入框。

 7.2.更珍视图

动用了Django的表单后,就要在视图中张开相应的校订:

# login/views.py

from django.shortcuts import render,redirect
from . import models
from .forms import UserForm

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

def login(request):
    if request.method == "POST":
        login_form = UserForm(request.POST)
        message = "请检查填写的内容!"
        if login_form.is_valid():
            username = login_form.cleaned_data['username']
            password = login_form.cleaned_data['password']
            try:
                user = models.User.objects.get(name=username)
                if user.password == password:
                    return redirect('/index/')
                else:
                    message = "密码不正确!"
            except:
                message = "用户不存在!"
        return render(request, 'login/login.html', locals())

    login_form = UserForm()
    return render(request, 'login/login.html', locals())

说明:

  • 对此非POST方法发送数据时,譬喻GET方法央求页面,重临空的表单,让顾客能够填入数据;
  • 对此POST方法,选取表单数据,并证实;
  • 采用表单类自带的is_valid()主意一步成功多少表达职业;
  • 注解成功后得以从表单对象的cleaned_data多少字典中获得表单的具体值;
  • 设若表明不通过,则赶回二个含有先前数码的表单给前端页面,方便客户改革。也正是说,它会帮您保存以前填写的数据内容,而不是回来三个空表!

其余,这里运用了二个小技巧,Python内置了叁个locals()函数,它回到当前具备的本地变量字典,大家得以偷懒的将那看作render函数的多寡字典参数值,就毫无费力去协会二个形如{'message':message, 'login_form':login_form}的字典了。这样做的益处当然是大大有帮忙了作者们,可是同期也是有可能往模板传入了有的剩余的变量数据,产生数据冗余裁减功用。

7.3.修改login界面

Django的表单很关键的一个作用正是自动生成HTML的form表单内容。今后,大家须求修正一下原先的login.html文件:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}<link href="{% static 'css/login.css' %}" rel="stylesheet"/>{% endblock %}


{% block content %}
    <div class="container">
        <div class="col-md-4 col-md-offset-4">
          <form class='form-login' action="/login/" method="post">

              {% if message %}
                  <div class="alert alert-warning">{{ message }}</div>
              {% endif %}
              {% csrf_token %}
              <h2 class="text-center">欢迎登录</h2>

              {{ login_form }}

              <button type="reset" class="btn btn-default pull-left">重置</button>
              <button type="submit" class="btn btn-primary pull-right">提交</button>

          </form>
        </div>
    </div> <!-- /container -->
{% endblock %}

浏览器生成的HTML源码

重新启航服务器,刷新页面,如下图所示:图片 11

图片 12

7.4.手动渲染表单

直接{{ login_form }}即使好,啥都并不是操心,可是分界面真的极丑,往往实际不是您想要的,即使您要动用CSS和JS,举个例子你要引入Bootstarps框架,那些都急需对表单内的input成分进行额外调整,那咋做吧?手动渲染字段就能够了。

能够经过{{ login_form.name_of_field }}获取每一个字段,然后分别渲染,如下例所示:

<div class="form-group">
  {{ login_form.username.label_tag }}
  {{ login_form.username}}
</div>
<div class="form-group">
  {{ login_form.password.label_tag }}
  {{ login_form.password }}
</div>

然后,在form类里足够attr属性就可以,如下所示改过login/forms.py

from django import forms

class UserForm(forms.Form):
    username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'}))
    password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))

再度刷新页面,就显得平时了!

 八、图片验证码

为了防卫机器人频仍登入网址仍然破坏分子恶意登陆,非常多顾客登陆和挂号系统都提供了图片验证码作用。

验证码(CAPTCHA卡塔 尔(阿拉伯语:قطر‎是“Completely Automated Public Turing test to tell 计算机s and Humans Apart”(全自动区分Computer和人类的图灵测量试验卡塔尔国的缩写,是大器晚成种有别于顾客是计算机照旧人的共用机关程序。能够幸免恶意破解密码、刷票、论坛灌注,有效防护有个别黑客对某多个一定注册顾客用特定程序暴力破解情势开展持续的登录尝试。

图表验证码的历史比较持久,到明天早原来就有一点英雄末路的意味了。因为机器学习、图像识其余留存,机器人已经能够比较不易的辨认图像内的字符了。但不管怎么说,作为风姿浪漫种防范花招,起码照旧得以抵御一些初级入门的抨击手腕,抬高了攻击者的技法。

在Django中达成图片验证码成效非常轻松,有现存的第三方库能够应用,大家不用本人开拓(也要能开垦得出去,囧卡塔尔。这么些库叫做django-simple-captcha

8.1.安装captcha

一直设置:pip install django-simple-captcha

Django自动帮我们设置了连带的信任库sixolefilePillow,此中的Pillow是资深的绘图模块。

注册captcha

在settings中,将‘captcha’注册到app列表里:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'login',
    'captcha',
]

captcha须要在数据库中创立和煦的数据表,所以要求推行migrate命令生成数据表:

python manage.py migrate

8.2.添加url路由

根目录下的urls.py文件中追加captcha对应的网站:

from django.conf.urls import url
from django.conf.urls import include
from django.contrib import admin
from login import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
    url(r'^login/', views.login),
    url(r'^register/', views.register),
    url(r'^logout/', views.logout),
    url(r'^captcha', include('captcha.urls'))  # 增加这一行
]

8.3.修改forms.py

假如地点都OK了,就足以间接在大家的forms.py文件中加多CaptchaField了。

from django import forms
from captcha.fields import CaptchaField

class UserForm(forms.Form):
    username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'}))
    password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    captcha = CaptchaField(label='验证码')

必要提前导入from captcha.fields import CaptchaField,然后就好像写普通的form字段同样增加二个captcha字段就可以了!

 8.4.修改login.html

 由于我们眼前是手动生成的form表单,所以还要改过一下,增加captcha的连带内容,如下所示:

{% extends 'login/base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}
    <link rel="stylesheet" href="{% static 'css/login.css' %}">
{% endblock %}


{% block content %}
    <div class="container">
        <div class="col-md-4 col-md-offset-4">
          <form class='form-login' action="/login/" method="post">

              {% if message %}
                  <div class="alert alert-warning">{{ message }}</div>
              {% endif %}
              {% csrf_token %}
              <h2 class="text-center">欢迎登录</h2>
              <div class="form-group">
                  {{ login_form.username.label_tag }}
                  {{ login_form.username}}
              </div>
              <div class="form-group">
                  {{ login_form.password.label_tag }}
                  {{ login_form.password }}
              </div>

              <div class="form-group">
                  {{ login_form.captcha.errors }}
                  {{ login_form.captcha.label_tag }}
                  {{ login_form.captcha }}
              </div>

              <button type="reset" class="btn btn-default pull-left">重置</button>
              <button type="submit" class="btn btn-primary pull-right">提交</button>

          </form>
        </div>
    </div> <!-- /container -->
{% endblock %}

此地额外扩充了一条{{ login_form.captcha.errors }}用以分明提醒顾客,你的验证码不得法

 查看效果:

图片 13

当中验证图形码是不是科学的做事皆以在后台自动完毕的,只要求运用is_valid()本条forms内置的表明形式就联合进行了,完全无需在视图函数中加上任何的印证代码,非常方便火速!

 九、session会话

        因为因特网HTTP公约的特点,每便来自于客户浏览器的号令(request卡塔尔国都以无状态的、独立的。通俗地说,正是敬敏不谢保存顾客情状,后台服务器根本就不精通当前哀告和早前及以往诉求是还是不是来自同风度翩翩客商。对于静态网址,那或然不是个难点,而对于动态网址,尤其是京东、天猫、银行等购物或金融网址,不能够辨别客商并维持客商意况是沉重的,根本就不或然提供劳务。你能够尝尝将浏览器的cookie功效关闭,你会意识将不可能在京东登入和购物。

为了兑现连接情况的维系作用,网址会由此顾客的浏览器在顾客机器内被节制的硬盘地方中写入一些数码,也正是所谓的库克ie。通过库克ie能够保留一些诸如客户名、浏览记录、表单记录、登入和撤回等种种数码。可是这种方式要命不安全,因为Cookie保存在客户的机器上,要是Cookie被冒用、点窜或删除,就能促成超级大的拉萨威逼,因此,现代网址设计日常将Cookie用来保存一些不首要的开始和结果,实际的客商数量和情景依旧以Session会话的艺术保留在服务器端。

Session信任Cookie!但与库克ie差异的地点在于Session将兼具的数码都投身服务器端,客商浏览器的Cookie中只会保留三个非明文的辨认音讯,比如哈希值。

Django提供了三个通用的Session框架,何况能够接收各个session数据的保存方法:

  • 保存在数据库内
  • 保存到缓存
  • 保存到文件内
  • 保存到cookie内

平时说来景况,未有特地须要的话,请使用保留在数据库内的措施,尽量不要保存到Cookie内。

Django的session框架私下认可启用,并曾经注册在app设置内,尽管实在未有启用,那么参照他事他说加以侦察下边包车型大巴内容增加有表达的这两行,再实行migrate命令创造数据表,就足以采取session了。

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',    # 这一行
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',  # 这一行
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

当session启用后,传递给视图request参数的HttpRequest对象将包含一个session属性,犹如三个字典对象雷同。你能够在Django的另各地点读写request.session个性,只怕一再编纂使用它。

上边是session使用参谋:

class backends.base.SessionBase
        # 这是所有会话对象的基类,包含标准的字典方法:
        __getitem__(key)
            Example: fav_color = request.session['fav_color']
        __setitem__(key, value)
            Example: request.session['fav_color'] = 'blue'
        __delitem__(key)
            Example: del request.session['fav_color']  # 如果不存在会抛出异常
        __contains__(key)
            Example: 'fav_color' in request.session
        get(key, default=None)
            Example: fav_color = request.session.get('fav_color', 'red')
        pop(key, default=__not_given)
            Example: fav_color = request.session.pop('fav_color', 'blue')

 # 类似字典数据类型的内置方法
        keys()
        items()
        setdefault()
        clear()


        # 它还有下面的方法:
        flush()
            # 删除当前的会话数据和会话cookie。经常用在用户退出后,删除会话。

        set_test_cookie()
            # 设置一个测试cookie,用于探测用户浏览器是否支持cookies。由于cookie的工作机制,你只有在下次用户请求的时候才可以测试。
        test_cookie_worked()
            # 返回True或者False,取决于用户的浏览器是否接受测试cookie。你必须在之前先调用set_test_cookie()方法。
        delete_test_cookie()
            # 删除测试cookie。
        set_expiry(value)
            # 设置cookie的有效期。可以传递不同类型的参数值:
        • 如果值是一个整数,session将在对应的秒数后失效。例如request.session.set_expiry(300) 将在300秒后失效.
        • 如果值是一个datetime或者timedelta对象, 会话将在指定的日期失效
        • 如果为0,在用户关闭浏览器后失效
        • 如果为None,则将使用全局会话失效策略
        失效时间从上一次会话被修改的时刻开始计时。

        get_expiry_age()
            # 返回多少秒后失效的秒数。对于没有自定义失效时间的会话,这等同于SESSION_COOKIE_AGE.
            # 这个方法接受2个可选的关键字参数
        • modification:会话的最后修改时间(datetime对象)。默认是当前时间。
        •expiry: 会话失效信息,可以是datetime对象,也可以是int或None

        get_expiry_date()
            # 和上面的方法类似,只是返回的是日期

        get_expire_at_browser_close()
            # 返回True或False,根据用户会话是否是浏览器关闭后就结束。

        clear_expired()
            # 删除已经失效的会话数据。
        cycle_key()
            # 创建一个新的会话秘钥用于保持当前的会话数据。django.contrib.auth.login() 会调用这个方法。

9.1.使用session

首先,修改login/views.py中的login()视图函数:

def login(request):
    if request.session.get('is_login',None):
        return redirect('/index')

    if request.method == "POST":
        login_form = UserForm(request.POST)
        message = "请检查填写的内容!"
        if login_form.is_valid():
            username = login_form.cleaned_data['username']
            password = login_form.cleaned_data['password']
            try:
                user = models.User.objects.get(name=username)
                if user.password == password:
                    request.session['is_login'] = True
                    request.session['user_id'] = user.id
                    request.session['user_name'] = user.name
                    return redirect('/index/')
                else:
                    message = "密码不正确!"
            except:
                message = "用户不存在!"
        return render(request, 'login/login.html', locals())

    login_form = UserForm()
    return render(request, 'login/login.html', locals())

透过上边包车型大巴if语句,大家不允许再一次登入:

if request.session.get('is_login',None):
    return redirect("/index/")

通过下边包车型客车言辞,大家往session字典内写入客户情形和数据:

request.session['is_login'] = True
request.session['user_id'] = user.id
request.session['user_name'] = user.name

你完全可今后里面写任何数据,不只限于顾客相关!

既然如此有了session记录顾客登入状态,那么就能够康健大家的登出视图函数了:

def logout(request):
    if not request.session.get('is_login', None):
        # 如果本来就未登录,也就没有登出一说
        return redirect("/index/")
    request.session.flush()
    # 或者使用下面的方法
    # del request.session['is_login']
    # del request.session['user_id']
    # del request.session['user_name']
    return redirect("/index/")

flush()方法是相比安全的风姿罗曼蒂克种做法,况且贰回性将session中的全部剧情全方位清空,确定保证不留后患。但也会有不好之处,那正是只要您在session中夹带了少数‘走私货色’,会被黄金时代并剔除,那一点一定要小心。

 9.2.康健页面

有了客户情状,就足以依附客商登录与否,显示不一样的页面,比方导航条内容:

首先,修改base.html文件:

 <div class="collapse navbar-collapse" id="my-nav">
          <ul class="nav navbar-nav">
            <li class="active"><a href="/index/">主页</a></li>
          </ul>
          <ul class="nav navbar-nav navbar-right">
              {% if request.session.is_login %}
                  <li><a href="#">当前在线:{{ request.session.user_name }}</a></li>
                  <li><a href="/logout/">登出</a></li>
              {% else %}
                  <li><a href="/login/">登录</a></li>
                  <li><a href="/register/">注册</a></li>
              {% endif %}
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->

因而if判别,当登陆时,突显当前客商名和发布开关。未登入时,呈现登入和注册按键。

介怀此中的模板语言,{{ request }}本条变量会被暗许传入模板中,能够通过圆点的调用情势,获取它里面包车型地铁{{ request.session }},再进一层的获得session中的内容。其实{{ request }}中的数据远不仅此,比方{{ request.path }}就足以获取先前的url地址。

再修正一下index.html页面,依据登陆与否的不等,显示区别的开始和结果:

{% extends 'base.html' %}
{% block title %}主页{% endblock %}
{% block content %}
    {% if request.session.is_login %}
    <h1>你好,{{ request.session.user_name }}!欢迎回来!</h1>
    {% else %}
    <h1>你尚未登录,只能访问公开内容!</h1>
    {% endif %}
{% endblock %}

看下效果:

图片 14

图片 15

 

 十、注册视图

 10.1.创建forms

/login/forms.py中增多四个新的表单类:

class RegisterForm(forms.Form):
    gender = (
        ('male', "男"),
        ('female', "女"),
    )
    username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'}))
    password1 = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    password2 = forms.CharField(label="确认密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    email = forms.EmailField(label="邮箱地址", widget=forms.EmailInput(attrs={'class': 'form-control'}))
    sex = forms.ChoiceField(label='性别', choices=gender)
    captcha = CaptchaField(label='验证码')

说明:

  • gender和User模型中的相像,其实能够拉出来作为常量共用,为了直观,特意重写叁遍;
  • password1和password2,用于输入五回密码,并举办相比较,避免误输密码;
  • email是一个邮箱输入框;
  • sex是一个select下拉框;

 10.2.完善register.html

相似地,相像login.html文件,大家在register.html中编辑forms相关条目款项:

{% extends 'login/base.html' %}

{% block title %}注册{% endblock %}
{% block content %}
    <div class="container">
        <div class="col-md-4 col-md-offset-4">
          <form class='form-register' action="/register/" method="post">

              {% if message %}
                  <div class="alert alert-warning">{{ message }}</div>
              {% endif %}

              {% csrf_token %}

              <h2 class="text-center">欢迎注册</h2>
              <div class="form-group">
                  {{ register_form.username.label_tag }}
                  {{ register_form.username}}
              </div>
              <div class="form-group">
                  {{ register_form.password1.label_tag }}
                  {{ register_form.password1 }}
              </div>
              <div class="form-group">
                  {{ register_form.password2.label_tag }}
                  {{ register_form.password2 }}
              </div>
              <div class="form-group">
                  {{ register_form.email.label_tag }}
                  {{ register_form.email }}
              </div>
              <div class="form-group">
                  {{ register_form.sex.label_tag }}
                  {{ register_form.sex }}
              </div>
              <div class="form-group">
                  {{ register_form.captcha.errors }}
                  {{ register_form.captcha.label_tag }}
                  {{ register_form.captcha }}
              </div>

              <button type="reset" class="btn btn-default pull-left">重置</button>
              <button type="submit" class="btn btn-primary pull-right">提交</button>

          </form>
        </div>
    </div> <!-- /container -->
{% endblock %}

10.3.挂号视图

进入/login/views.py文本,今后来康健大家的register()视图:

def register(request):
    if request.session.get('is_login', None):
        # 登录状态不允许注册。你可以修改这条原则!
        return redirect("/index/")
    if request.method == "POST":
        register_form = RegisterForm(request.POST)
        message = "请检查填写的内容!"
        if register_form.is_valid():  # 获取数据
            username = register_form.cleaned_data['username']
            password1 = register_form.cleaned_data['password1']
            password2 = register_form.cleaned_data['password2']
            email = register_form.cleaned_data['email']
            sex = register_form.cleaned_data['sex']
            if password1 != password2:  # 判断两次密码是否相同
                message = "两次输入的密码不同!"
                return render(request, 'login/register.html', locals())
            else:
                same_name_user = models.User.objects.filter(name=username)
                if same_name_user:  # 用户名唯一
                    message = '用户已经存在,请重新选择用户名!'
                    return render(request, 'login/register.html', locals())
                same_email_user = models.User.objects.filter(email=email)
                if same_email_user:  # 邮箱地址唯一
                    message = '该邮箱地址已被注册,请使用别的邮箱!'
                    return render(request, 'login/register.html', locals())

                # 当一切都OK的情况下,创建新用户

                new_user = models.User.objects.create()
                new_user.name = username
                new_user.password = password1
                new_user.email = email
                new_user.sex = sex
                new_user.save()
                return redirect('/login/')  # 自动跳转到登录页面
    register_form = RegisterForm()
    return render(request, 'login/register.html', locals())

从大要上逻辑上,也是先实例化二个RegisterForm的对象,然后利用is_valide()证实数据,再从cleaned_data中获取数据。

关键在于注册逻辑,首先五次输入的密码必需意气风发致,其次不可能存在同样客户名和邮箱,最终只要基准都满意,利用ORM的API,创制三个客户实例,然后保留到数据库内。

看一下报了名的页面:

图片 16

注册成功在admin后台能够见到登记的顾客

图片 17

10.4.密码加密

客户注册的密码应该加密才对

对此怎么加密密码,有众多不如的门路,其安全程度也高低不等。这里大家使用Python内置的hashlib库,使用哈希值的章程加密密码,也许安全等第相当的矮,但丰裕简单,方便使用,不是么?

首先在login/views.py中编辑一个hash函数:

import hashlib

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

接下来,大家还要对login()和register()视图举办一下退换:

#login.html

if user.password == hash_code(password):  # 哈希值和数据库内的值进行比对

#register.html

new_user.password = hash_code(password1)  # 使用加密密码

图片 18图片 19

# login/views.py

from django.shortcuts import render,redirect
from . import models
from .forms import UserForm,RegisterForm
import hashlib

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

def login(request):
    if request.session.get('is_login', None):
        return redirect("/index/")
    if request.method == "POST":
        login_form = UserForm(request.POST)
        message = "请检查填写的内容!"
        if login_form.is_valid():
            username = login_form.cleaned_data['username']
            password = login_form.cleaned_data['password']
            try:
                user = models.User.objects.get(name=username)
                if user.password == hash_code(password):  # 哈希值和数据库内的值进行比对
                    request.session['is_login'] = True
                    request.session['user_id'] = user.id
                    request.session['user_name'] = user.name
                    return redirect('/index/')
                else:
                    message = "密码不正确!"
            except:
                message = "用户不存在!"
        return render(request, 'login/login.html', locals())

    login_form = UserForm()
    return render(request, 'login/login.html', locals())


def register(request):
    if request.session.get('is_login', None):
        # 登录状态不允许注册。你可以修改这条原则!
        return redirect("/index/")
    if request.method == "POST":
        register_form = RegisterForm(request.POST)
        message = "请检查填写的内容!"
        if register_form.is_valid():  # 获取数据
            username = register_form.cleaned_data['username']
            password1 = register_form.cleaned_data['password1']
            password2 = register_form.cleaned_data['password2']
            email = register_form.cleaned_data['email']
            sex = register_form.cleaned_data['sex']
            if password1 != password2:  # 判断两次密码是否相同
                message = "两次输入的密码不同!"
                return render(request, 'login/register.html', locals())
            else:
                same_name_user = models.User.objects.filter(name=username)
                if same_name_user:  # 用户名唯一
                    message = '用户已经存在,请重新选择用户名!'
                    return render(request, 'login/register.html', locals())
                same_email_user = models.User.objects.filter(email=email)
                if same_email_user:  # 邮箱地址唯一
                    message = '该邮箱地址已被注册,请使用别的邮箱!'
                    return render(request, 'login/register.html', locals())

                # 当一切都OK的情况下,创建新用户

                new_user = models.User.objects.create()
                new_user.name = username
                new_user.password = hash_code(password1)  # 使用加密密码
                new_user.email = email
                new_user.sex = sex
                new_user.save()
                return redirect('/login/')  # 自动跳转到登录页面
    register_form = RegisterForm()
    return render(request, 'login/register.html', locals())

def logout(request):
    if not request.session.get('is_login',None):
        return redirect('/index/')
    request.session.flush()

    return redirect('/index/')

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

views.py全体代码

重启服务器,步向注册页面,新建三个客户,然后步向admin后台,查看客户的密码情状:

图片 20

 再采纳该客商登陆一下,马到功成!

能够看看密码长度依据你哈希算法的两样,已经变得相当长了,所早先边model中设置password字段时,不要想当然的将max_length设置为16如此小的数字。

 

本文由67677新澳门手机版发布于计算机编程,转载请注明出处:Django客商登录与注册系统

关键词: