首先搭建蓝图
- 用户登录功能
- 知识回顾1,使用MD5加密密码
import hashlib
# md5加密功能
hash = hashlib.md5(b'dkfjdfj') # 加盐
hash.update(bytes('123', encoding='utf-8'))
ret = hash.hexdigest()
print(ret)
加密后的123
D:\python3.6\python.exe
2756aee19e1944dd1efd7d5fc9ed0fe9
Process finished with exit code 0
把加密后的密文存进数据库中的用户信息
-
知识回顾2使用pymysql
步骤
1 建立连接
2 获取光标
3 执行sql语句
4 获取结果
如图
fetchone获取符合条件的一条数据
fetchall获取全部信息
-
关于pymysql语句注入的问题:
sql语句中如果自己使用字符串拼接,mysql中1=1永远成立,所以就算条件没有通过也会执行前面的sql语句
如图
py文件中执行结果,即使用户名不正确也可以获取到执行sql语句
navicat同样可以执行
也就是说用户输入以下用户名是可以登录的
解决方法
使用sql注入可以避免以上问题
防止时不要用字符串格式化拼接就可以了
格式如图
也可以不用元祖,通过字典的形式注入
- 把以上代码放到项目中
首先开启manage脚本
自动运行__init__文件
找到对应的路由
如路由是login
则运行以下文件
如果用户名和密码正确跳到了路由/home
于是执行以下蓝图
没有session重新登录,有session跳到home页面
附
settings中的类
模版文件login.html
utils中的md5加密函数
试运行:
2. 展示用户列表功能
登录成功后显示首页
效果如图
代码:
新建继承的模版
home页面引用模版,把内容填充到block content中
- 点击注销,跳转到login页面,同时删除session
- 点击用户列表,查看所有用户信息
前端效果图:
代码
从数据库获取到所有用户,返回给html
4. 查看代码统计量
新建表
点击查看,登录到detail/id页面,可以看到相关用户的代码行
如图
代码
同样也是在数据库中找到指定用户的所有信息,再返回给html
html文件中只需循环记录,显示在表格中
3. 上传zip文件和解压
点击上传按钮,跳到upload页面
html代码
上传的文件后天接收后解压到指定目录
效果如图
- 统计代码行数功能
知识回顾 os.walk
os.walk把指定文件夹中的所有文件夹和文件都递归地找出来
字典中三个值,第一是所在目录,第二个是文件夹,第三个是文件
运行结果
- 每日提交一次功能
首先连接数据库,然后把代码行插入到数据库
- 数据库连接池DBUtils的使用
每次请求都创建连接,创建cusor,关闭连接,
能否只创建一个连接,以后都用一个连接,如果项目启动起来就创建一个连接,一个线程,来一次处理一次,还不能关闭连接,操作完后拿结果,
但如果是多线程,就会混乱,
所以如果用一个连接,支持不了多线程,如果用每个连接,连接开关次数太多,所以要用数据库连接池做,
使用DBUtIls
pip3 install DBUtils
不管有多少个线程,就创建10个连接池,如有10个人同时来了,把十个连接拿走,第十一个人来了就等,
使用pymysql,帮我们控制连接池,连接池作用是什么,程序运行时,连接来时和数据库先创建3个连接,
使用DBUtils:
from DBUtils.PooledDB import PooledDB, SharedDBConnection
import pymysql
POOL = PooledDB(
creator=pymysql,
maxconnections=6, # 最大连接数,连接池最多开6个连接,
mincached=2, # 初始化时是2个,如果没有6个连接,先开2个,不够再开
maxcached=5, # 最多闲置的连接,如开始开了6个,如果不用,再关闭几个,节约数据库资源,最多留几个连接
maxshared=3, # 最多共享几个,因为python不支持多线程,threading默认为1,所以该值不管写多少个都是0
blocking=True, # 如果连接池里面没有连接了,就等,如果是False,直接报错,就扑捉错误
maxusage=None, # 连接池里面6个连接,一直在用,可以设置连接被用了100次后,就关闭,再重新创
setsession=[], # 执行命令前执行的sql命令,如设置字符集,时间等
ping=0, # 连接前先ping一下,看网络是不是通的,ping = 0/None/never ,表示永远不检查,拿了连接直接发sql就行了,1 = default 每次发送请求时执行 whenever it is requested,2 = when a cursor is created, 4 = 执行.excute时 ,7 但凡有数据库操作都是要ping
host='127.0.0.1',
port=3306,
user='root',
password='123',
database='codestatisc',
charset='utf8',
)
def task():
conn = POOL.connection() # 在连接池里面拿出一个连接来,
cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.execute('select sleep(2)') # 查数据库,执行一个停2秒
result = cursor.fetchall()
cursor.close()
conn.close() # 归还到数据库连接池
print(result)
import threading
for i in range(30): # 开30个线程
t = threading.Thread(target=task) # 运行task
t.start() # 线程开始运行
运行结果
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
[{'sleep(2)': 0}]
运用到flask
如果创建很多连接池,浪费资源,所以要以单例模式存在,放到settings中
account中就不用连接数据库了
同样index文件中也需要改
提高代码重用性,
fetchone,fetchall,insert 用的比较多
在utils中新建helper写3个方法
from settings import Config
import pymysql
def open():
conn = Config.POOL.connection()
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
return conn, cursor
def close(conn, cursor):
cursor.close()
conn.close()
def fetch_all(sql, args): # 传sql语句和条件
conn, cursor = open()
cursor.execute(sql, args)
record_list = cursor.fetchall()
close(conn, cursor)
return record_list
def fetch_one(sql, args): # 传sql语句和条件
conn, cursor = open()
cursor.execute(sql, args)
result = cursor.fetchone()
close(conn, cursor)
return result
def insert(sql, args): # 传sql语句和条件
conn, cursor = open()
row = cursor.execute(sql, args)
conn.commit()
close(conn, cursor)
return row # 受影响的行数,如插入1条返回1
在account和index中使用helper中的方法
制作折线图网站 https://www.hcharts.cn/
柱状图
select user_id, sum(line) from record group by user_id + 连表查询到用户姓名