饮冰三年-人工智能-Python-42 Python之Flask中的WTForm+DBUtils实现学生管理系统 一、基于DBUtils实现数据库连接池 二、数据准备    三、代码结构和MYSQLHelper工具类   四、WTForm实现登录校验  五、学生信息的维护

上篇中 我们通过Flask蓝图简单做了一个增删改查的学生管理系统,在数据和页面校验上都存在很大问题。接下来我们完善一下。

代码存储:GitHub

1:原理浅析 

  连接池:是创建和管理连接的缓存池。简单的说:随时准备着。有一些国外学者喜欢称之曰“备胎”。
  优点
    一:减少连接创建时间
    二:受控的资源使用
    连接池能够使性能最大化,同时还能将资源利用控制在一定的水平之下,如果超过该水平,应用程序将崩溃而不仅仅是变慢。
  原理与操作 
(1)建立数据库连接池对象(服务器启动)。
(2)按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。
(3)对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接。
(4)存取数据库。
(5)关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接数大于初始空闲连接数则释放连接)。
(6)释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)

2:连接练习

  1:首先安装DBUtils 和 PyMySQL

饮冰三年-人工智能-Python-42 Python之Flask中的WTForm+DBUtils实现学生管理系统
一、基于DBUtils实现数据库连接池
二、数据准备   
三、代码结构和MYSQLHelper工具类  
四、WTForm实现登录校验 
五、学生信息的维护
from flask import Flask
import pymysql
import time
from DBUtils.PooledDB import PooledDB, SharedDBConnection

# 创建共享连接池
POOL = PooledDB(
    creator=pymysql,  # 使用链接数据库的模块
    maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
    mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建

    maxcached=5,  # 链接池中最多闲置的链接,0和None不限制
    maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制,连接使用次数过多会有缓存,有时需要使用最新的
    setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]

    maxshared=3,
    # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。

    blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
    ping=0,
    # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
    host='127.0.0.1',
    port=3306,
    user='root',
    password='',
    database='yk2012',
    charset='utf8',
)


# 记忆方法
# 模块 最大 初始化
# 闲置 最新 开始化
# 阻塞 检查 基本化

def get_conn():
    """
    连接数据库
    :return: conn, cursor
    """
    conn = POOL.connection()  # 数据库连接
    cursor = conn.cursor(pymysql.cursors.DictCursor)  # 数据库指针
    return conn, cursor


def reset_conn(conn, cursor):
    """
     :param conn: 数据库连接
     :param cursor: 数据库指针
     :return: Null
     """
    cursor.close()
    conn.close()


def fetch_all(sql, args):
    """
    :param sql: sql语句
    :param args: sql语句的参数
    :return: 查询结果
    """
    conn, cursor = get_conn()
    cursor.execute(sql, args)
    result = cursor.fetchall()
    reset_conn(conn, cursor)
    return result

app=Flask(__name__)
@app.route('/')
def index():
    res=fetch_all("select * from student",())
    print(res)
    return "执行成功"

if __name__ == '__main__':
    app.run(debug=True)
DBUtils

总结:配置项记忆方法

# 模块 最大 初始化
# 闲置 最新 开始化
# 阻塞 检查 基本化

二、数据准备   

1:创建相应的数据库和数据表

  首先,我们创建一个数据库(StudentManage_WTF)。

  再创建一个用户表(User){ID:自增,UserName:用户名, Password:密码}

  再创建一个学生表(Student){ID:自增, StudentName: 姓名,Age:年龄, Gender:性别}  

#创建数据库
create database StudentManage_WTF;
#创建用户表
create table User(
    ID int primary key auto_increment,
    UserName nvarchar(20) not null,
    Password nvarchar(200) not null
);
#初始化管理员
insert into User (UserName,Password) Values('Aaron','1');
#创建学生信息表
create table Student(
    ID int primary key auto_increment,
    StudentName nvarchar(20) not null,
    Age int,
    Gender int
);
数据库创建脚本

三、代码结构和MYSQLHelper工具类  

1:代码结构

饮冰三年-人工智能-Python-42 Python之Flask中的WTForm+DBUtils实现学生管理系统
一、基于DBUtils实现数据库连接池
二、数据准备   
三、代码结构和MYSQLHelper工具类  
四、WTForm实现登录校验 
五、学生信息的维护

2:帮助类MYSQLHelper

from flask import Flask
import pymysql
import time
from DBUtils.PooledDB import PooledDB, SharedDBConnection


class MYSQLHelper(object):
    def __init__(self, host, port, dbuser, password, database):
        self.pool = PooledDB(
            creator=pymysql,  # 使用链接数据库的模块
            maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
            mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
            maxcached=5,  # 链接池中最多闲置的链接,0和None不限制
            maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制,连接使用次数过多会有缓存,有时需要使用最新的
            setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
            maxshared=3,
            # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
            blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
            ping=0,
            # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
            host=host,
            port=int(port),
            user= dbuser,
            password=password,
            database= database,
            charset='utf8',
        )


    def get_conn(self):
        """
        连接数据库
        :return: conn, cursor
        """
        conn = self.pool.connection()  # 数据库连接
        cursor = conn.cursor(pymysql.cursors.DictCursor)  # 数据库指针
        return conn, cursor


    def reset_conn(self,conn, cursor):
        """
         :param conn: 数据库连接
         :param cursor: 数据库指针
         :return: Null
         """
        cursor.close()
        conn.close()


    def fetch_all(self,sql, args):
        """
        :param sql: sql语句
        :param args: sql语句的参数
        :return: 查询结果
        """
        conn, cursor = self.get_conn()
        cursor.execute(sql, args)
        result = cursor.fetchall()
        self.reset_conn(conn, cursor)
        return result

    def insert_one(self,sql,args):
        conn,cursor=self.get_conn()
        res=cursor.execute(sql,args)
        conn.commit()
        self.reset_conn()
        return res

    def update(self,sql,args):
        conn,cursor=self.get_conn()
        result = cursor.execute(sql,args)
        conn.commit()
        self.reset_conn()
        return result
MYSQLHelper.py

四、WTForm实现登录校验 

1:登录页面

  a:使用数据库中User表判断是否有权限。

  b:使用WTForm框架做校验。

#1:安装WTForms!ps:别安装错了,不是WTForm
from wtforms.fields import simple,core
from wtforms import Form,validators,widgets

class LoginForm(Form):
    username =simple.StringField(
        label="用户名",
        validators=[
            validators.data_required(message="用户名不能为空")
        ],
        widget=widgets.TextInput(),
        render_kw={"class":"my_username"}
    )
    password =simple.StringField(
        label="密码",
        validators=[
            validators.data_required(message="密码不能为空!")
        ],
        widget=widgets.PasswordInput()
    )
    submit=simple.SubmitField(
        label="提交"

    )
ModelForm
{% extends "index.html" %}
{% block css %}
    <style>
        label[for='submit'] {
            display: none
        }
    </style>
{% endblock %}
{% block content %}
    <h2>学生登录</h2>
    <form action="/s_login" method="post" novalidate>
        {% for filed in loginForm %}
            <p>{{ filed.label }} {{ filed }}{{ filed.errors.0 }}</p>
        {% endfor %}
    </form>
{% endblock %}
s_login.html
from flask import Blueprint
from flask import render_template, request, session, redirect
from StudentManage_WTF.Tools.Helper.DBHelper.MYSQLHelper import MYSQLHelper
from StudentManage_WTF.UserLogin.ModelForm.LoginModel import LoginForm

# 每个蓝图都可以为自己独立出一套template模板文件夹,如果不写则共享项目目录中的templates
sl = Blueprint("sl", __name__, template_folder="templates")


@sl.route("/s_login", methods=("GET", "POSt"))
def userLogin():
    if request.method == "GET":
        loginForm = LoginForm()
        return render_template("s_login.html", loginForm=loginForm)
    else:
        lf = LoginForm(request.form)
        if lf.validate():
            username = request.form.get("username")
            password = request.form.get("password")
            # 获取sql帮助类对象
            sqlhelper = MYSQLHelper("127.0.0.1", 3306, "root", "", "StudentManage_WTF")
            # 拼接sql语句
            sql = "select id,username from user where username='%s' and password='%s'" % (username, password)
            res = sqlhelper.fetch_all(sql, ())
            print(res)
            if res:
                session["user"] = res
                return redirect("/s_view")
            else:
                session["user"] = None
                lf.username.errors.append("用户名或密码错误!")
                return render_template("s_login.html", loginForm=lf)
        else:
            return render_template("s_login.html", loginForm=lf)
login.py

饮冰三年-人工智能-Python-42 Python之Flask中的WTForm+DBUtils实现学生管理系统
一、基于DBUtils实现数据库连接池
二、数据准备   
三、代码结构和MYSQLHelper工具类  
四、WTForm实现登录校验 
五、学生信息的维护

五、学生信息的维护

1:学生列表页面

from flask import Blueprint
from flask import render_template
from StudentManage_WTF.Tools.Helper.DBHelper.MYSQLHelper import MYSQLHelper
# 每个蓝图都可以为自己独立出一套template模板文件夹,如果不写则共享项目目录中的templates
sv = Blueprint("sv", __name__, template_folder="templates")


@sv.route("/s_view")
def studentView():
    # 获取sql帮助类对象
    sqlhelper = MYSQLHelper("127.0.0.1", 3306, "root", "", "StudentManage_WTF")
    # 拼接sql语句
    sql = "select * from Student where 1=1"
    studentList = sqlhelper.fetch_all(sql, ())
    return render_template("s_view.html", studentList=studentList)
s_view.py
{% extends "index.html" %}
{% block content %}
    <h2>学生列表</h2>
    <table border="3xp">
        <thead>
        <tr>
            <td>编号</td>
            <td>学生姓名</td>
            <td>年龄</td>
            <td>性别</td>
            <td>操作</td>
        </tr>
        </thead>
        <tbody>
        {% for student in studentList %}
            <tr>
                <td>{{ student.ID }}</td>
                <td>{{ student["StudentName"] }}</td>
                <td>{{ student.get("Age") }}</td>
                <td>{{ student.Gender }}</td>
                <td><a href="/s_update/{{ student.ID }}">修改</a> | <a href="/s_del?id={{ student.ID }}">删除</a></td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
    <a href="/s_add">新增</a>
{% endblock %}
s_view.html

饮冰三年-人工智能-Python-42 Python之Flask中的WTForm+DBUtils实现学生管理系统
一、基于DBUtils实现数据库连接池
二、数据准备   
三、代码结构和MYSQLHelper工具类  
四、WTForm实现登录校验 
五、学生信息的维护

2:学生管理页面

from flask import Blueprint
from flask import render_template, request, redirect
from StudentManage_WTF.student_oper.ModelForm.StudentModel import StudentForm
from StudentManage_WTF.configer.MYSQLSetting import getMYSQLHelper

# 每个蓝图都可以为自己独立出一套template模板文件夹,如果不写则共享项目目录中的templates
sa = Blueprint("sa", __name__, template_folder="templates")
sqlhelper = getMYSQLHelper()


@sa.route("/s_add", methods=('GET', 'POST'))
def studentAdd():
    if request.method == "GET":
        stu = StudentForm()
        return render_template("s_add_modify.html", curTitle="新增", curAction="/s_add", stu=stu)
    else:
        stu = StudentForm(request.form)
        if stu.validate():
            # 获取sql帮助类对象
            # 拼接sql语句
            sql = "insert into student (studentname,age,gender) values('%s',%s,%s);" % (
                stu.StudentName.data, stu.Age.data, stu.Gender.data)
            res = sqlhelper.insert_one(sql, ())
            return redirect("/s_view")
        else:
            return render_template("s_add_modify.html", curTitle="新增", curAction="/s_add", stu=stu)


@sa.route("/s_update/<int:id>", methods=('GET', 'POST'))
def studentUpdate(id):
    if request.method == "GET":
        sql = "select * from student where ID='%s'" % (id)
        curStu = sqlhelper.fetch_all(sql, ())
        if curStu:
            curStu = StudentForm(**curStu[0])  # 神来之笔
        return render_template("s_add_modify.html", curTitle="编辑", curAction="/s_update/" + str(id), stu=curStu)
    else:
        stu = StudentForm(request.form)
        if stu.validate():
            sql = "update student set studentname='%s',age='%s',gender='%s' where ID='%s'" 
                  % (stu.StudentName.data, stu.Age.data, stu.Gender.data, id)
            res = sqlhelper.update(sql, ())
            return redirect("/s_view")
        else:
            return render_template("s_add_modify.html", curTitle="编辑", curAction="/s_update/" + str(id), stu=stu)


@sa.route("/s_del", methods=('GET', 'POST'))
def studentDel():
    id = request.args.get('id')
    sql = "delete from student where ID='%s'" % (id)
    curStu = sqlhelper.update(sql, ())
    return redirect("/s_view")
s_add_modify_del.py方法
from wtforms.fields import simple, core
from wtforms import widgets, validators, Form


class StudentForm(Form):
    ID = simple.StringField(
        widget=widgets.HiddenInput
    ),
    StudentName = simple.StringField(
        label="姓名",
        validators=[
            validators.data_required(message="学生姓名不能为空!"),
            validators.Length(min=2, max=20, message="学生姓名长度必须大于2位,小于20位")
        ]
    )
    Age = core.StringField(
        label="年龄",
        validators=[
            validators.data_required(message="学生年龄不能为空!"),
            validators.Regexp(regex="^d+$", message="学生年龄必须为数字")
        ]
    )
    Gender = core.RadioField(
        label="性别",
        coerce=int,  # 保存到数据中的值为int类型
        choices=(
            (0, ''), (1, '')
        ),
        default=1
    )
    submit = simple.SubmitField(
        label="提交"
    )
StudentModel
{% extends "index.html" %}
{% block css %}
    <style>
        label[for='submit'] {
            display: none
        }
    </style>
{% endblock %}
{% block content %}
    <h2>学生{{ curTitle }}</h2>
    <form action="{{ curAction }}" method="post" novalidate>
        {% for filed in stu %}
            <p>{{ filed.label }} {{ filed }}{{ filed.errors.0 }}</p>
        {% endfor %}
    </form>
{% endblock %}
s_add_modify.html

饮冰三年-人工智能-Python-42 Python之Flask中的WTForm+DBUtils实现学生管理系统
一、基于DBUtils实现数据库连接池
二、数据准备   
三、代码结构和MYSQLHelper工具类  
四、WTForm实现登录校验 
五、学生信息的维护饮冰三年-人工智能-Python-42 Python之Flask中的WTForm+DBUtils实现学生管理系统
一、基于DBUtils实现数据库连接池
二、数据准备   
三、代码结构和MYSQLHelper工具类  
四、WTForm实现登录校验 
五、学生信息的维护