flask

python轻量级web框架,本身就是个中间件,借助操作系统的python环境去运行


flask基本设置

目录下新建几个文件夹

static

templates

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import flask
from flask import Flask

# 创建flask程序
app = Flask(__name__,
static_url_path='/static', # 静态文件路径
static_folder='static',
template_folder='templates' # 模板文件
)

@app.route('/') # 路由 = 什么路径可以访问到什么资源
def index():
return "this is index"

if __name__ == '__main__':
app.run() # 运行,默认ip:127.0.0.1 端口:5000

运行也可以app.run(host='0.0.0.0',port=8888,debug=True)

host=’0.0.0.0’是开放所有ip,包括内网,公网,如果在公网服务器运行就可以被全世界访问到了

port设置端口

debug=True开启调试模式,一般在本地开发时使用,在更改代码后不需要重启服务器,代码运行出错可以在网页中显示代码出错原因


flask请求和参数

get类型请求及传参

分两种

第一种,个人觉得不好记

1
2
3
4
@app.route('/a/<id>/<password>')
def a_page(id,password):
return "您的id:%s---您的password:%s"%(id,password)
pass

访问时参数样式如下

http://127.0.0.1:8888/test/123/123

第二种

1
2
3
4
5
@app.route('/a',methods=['GET'])
def a_page():
user_id = request.args.get('id')
user_pass = request.args.get('password')
return "您的id:%s---您的password:%s"%(user_id,user_pass)

访问时参数样式如下,注意访问的参数是request.args.get('')里面的

http://127.0.0.1:8888/test?id=123&password=123


post类型请求和传参

1
2
3
4
5
@app.route('/a',methods=['POST']) # 不写method默认get类型
def a_page():
user_id = request.form.get('id')
user_pass = request.form.get('password')
return "您的id:%s---您的pass:%s"%(user_id,user_pass)

post类型访问。。。一般这是开发者给你写好了怎么传参,比如弄个输入框什么的,但这个时候我们就是开发者。。。所以个人建议浏览器下个叫做hackbar的插件,可以很方便的使用post请求


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import flask
from flask import request
from flask import Flask

# 创建flask程序
app = Flask(__name__,
static_url_path='/static', # 静态文件路径
static_folder='static',
template_folder='templates' # 模板文件
)

# @app.route('/a/<id>/<password>') # 路由 = 什么路径可以访问到什么资源
# def a_page(id,password):
# return "您的id:%s---您的password:%s"%(id,password)
# pass

# @app.route('/a',methods=['GET'])
# def a_page():
# user_id = request.args.get('id')
# user_pass = request.args.get('password')
# return "您的id:%s---您的pass:%s"%(user_id,user_pass)

@app.route('/a',methods=['POST'])
def a_page():
user_id = request.form.get('id')
user_pass = request.form.get('password')
return "您的id:%s---您的password:%s"%(user_id,user_pass)

# 装饰器,关联路由
@app.route('/') # 路由 = 什么路径可以访问到什么资源
def index():
return "haha"
pass

if __name__ == '__main__':
app.run(host='0.0.0.0',port=8888,debug=True)

flask中的request库

当然我们也注意到很多信息都是通过request库获取的,事实上还有很多信息能获取

request.method 获取请求类型

request.headers 获取请求头

request.headers.get(“User-agent”) 获取请求头中的某项信息,这里是浏览器

request.path 获取路径,比如/abc

request.full_path 获取整个路径的请求(包括参数),比如/abc?uname=xxx&upass=xxx

request.baseurl 获取访问的完整url(不包括参数),比如 http://127.0.0.1:8888/abc

request.url 获取访问的完整url(包括参数),比如 http://127.0.0.1:8888/abc?uname=11&upass=aa

request.user_agent 获取访问者信息

request.user_agent.platform 客户端操作系统

request.user_agent.browser 客户端浏览器

request.user_agent.version 客户端浏览器版本

request.user_agent.language 客户端浏览器语言

能获取的东西非常多,这里不做赘述


json和字典

网站交互一般返回json格式的数据,比如

{“name”:”xiaoming,”pass”,”aaaa”}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import flask
from flask import Flask
from flask import json

# 创建flask程序
app = Flask(__name__,
static_url_path='/static', # 静态文件路径
static_folder='static',
template_folder='templates' # 模板文件
)

@app.route('/') # 路由 = 什么路径可以访问到什么资源
def index():
return "this is index"

@app.route('/a')
def a_page():
# 定义一个字典
json_dict = {
"name":"xiaoming",
"age":"89",
"score":"100"
}
# 字典转化为json字符串
result = json.dumps(json_dict)
# return result
# json转化为字典
dict1 = json.loads('{"age":99,"name":"xiaoming","score":"100"}')
print(dict1["name"])

if __name__ == '__main__':
app.run(host='0.0.0.0',port=8888,debug=True)

重定向

就是说你输入到一个url,然后自动给你跳到另一个url

1
2
3
4
5
6
@app.route('/redirect')
def b_page():
# 站外重定向
return flask.redirect('http://www.baidu.com') # 重定向到百度
# 站内重定向
return flask.redirect(flask.url_for('index')) # 站内重定向的位置要写函数名,这里跳转到index

404重定向

这个404重定向比较特殊,是你访问不存在的页面全都重定向到你设置好的404页面

1
2
3
@app.errorhandler(404)
def page_not_found(e):
return '出错了,不存在',404

url别名

如果访问的url非常非常长,可以设置一个别名,这里通过重定向来实现

1
2
3
4
5
6
7
@app.route('/henchanghenchanghenchang',endpoint='l1')
def henchang():
return "很长url的页面"

@app.route('/a')
def a_page():
return flask.redirect(flask.url_for('l1')) # 跳转到url很长的页面

异常处理

主动抛出404异常,程序自动转到404

1
2
3
4
5
@app.route('/a')
def a_page():
# 主动抛出异常
flask.abort(404)
return 'a page'

如果在return后面加上状态码404,访问页面后可以显示正常的内容,但是返回的状态码是404

有时候黑客的扫描器扫出来只会看200的结果,忽略404,这些404结果可能确实有资产但是返回404容易被忽略

1
2
3
@app.route('/a')
def a_page():
return 'a page',404

html返回

1
2
3
4
5
6
7
from flask import Response
@app.route('/a')
def a_page():
# 可以返回html代码
return Response('<h1>haha nihao</h1>'
'<br><hr>'
'<h2>aaaaaaaa</h2>')

模板

可以在templates目录下新建html文件,这里新建temp.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路由测试</title>
</head>
<body>
<h1>i am temp html</h1>
</body>
</html>
1
2
3
4
@app.route('/a')
def a_page():
# 使用temp.html模板
return flask.render_template('temp.html')

显示的是temp.html的模板的内容


继承

templates目录下

father.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路由测试</title>
</head>
<body>
<h1>i am father temp</h1>

{% block contentBlock %}<!--继承开始位置-->
<h1>father html temp</h1>
{% endblock %}<!--继承结束位置-->
<h1>i am father last</h1>
</body>
</html>

child.html

1
2
3
4
5
6
7
{% extends 'father.html' %}<!--继承父页面-->

{% block contentBlock %}<!--继承开始-->

{{super()}}<!--继承内容-->
<h2>zi mo ban</h2><!--子页面自己的内容-->
{% endblock %}<!--继承结束位置-->

py文件

1
2
3
@app.route('/a')
def a_page():
return flask.rander_template('child.html')

可以看到子页面继承了父页面的内容


模板传参

Jinja2模板

渲染!!!!

互动

{{x}}存放变量

{%...%}控制代码块

``注释符

通过get传入的参数也可以显示出来,post同理

1
2
3
4
5
6
7
8
@app.route('/a/<id>')
def a_page(id):
# python参数进来都是string类型,有时候需要进行强制类型转换
m_int = int(id)+20
m_str = "haha nihao"
m_list = ["xiaoming","xiaohong","xiaoli"]
vip = 1
return flask.render_template("temp.html",mint=m_int,mstr=m_str,mlist=m_str,vip=vip)

temp.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路由测试</title>
</head>
<body>
<h1>i am temp html</h1>
mint = {{mint}} --- mstr = {{mstr}} --- mlist = {{mlist}}
vip = {{vip}}
</body>
</html>

访问http://127.0.0.1/1/20,可以看到mint变成了40

也可以看到mstr,mlist,vip等都是我们设定的值,相当于后端的变量传到前端


过滤器

py文件

1
2
3
4
5
@app.template_filter('dore')
def do_reserve(li):
temp = list(li)
temp.reserve()
return temp

temp.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路由测试</title>
</head>
<body>
<h1>i am temp html</h1>
mint = {{mint}} --- mstr = {{mstr}} --- mlist = {{mlist}}
reverse is {{mlist|dore}}
vip = {{vip}}
</body>
</html>

可以看到mlist反了过来

这里的过滤器表示把列表内的元素倒过来输出


控制代码块

temp.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路由测试</title>
</head>
<body>
<h1>i am temp html</h1>
mint = {{mint}} --- mstr = {{mstr}} --- mlist = {{mlist}}
reverse is {{mlist|dore}}
<br>
{% for item in mlist %}
<li>{{item}}</li>
{% endfor %}
<br>
{% for num in range(1,10) %}
<li>{{num}}</li>
{% endfor %}
<br>
vip = {{vip}}
{% if vip == "0" %}
<h1>你没充钱</h1>
{% elif vip == "1" %}
<h1>lv1的内容</h1>
<% endif %>

</body>
</html>

这里以for循环和if语句为例展示控制代码块


cookie交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Response

@app.route('/a')
def a_page():
# 读取cookie
user_id = request.cookies.get('user_id')
vip = request.cookies.get('vip')
return flask.render_template('temp.html',user_id=user_id,vip=vip)

@app.route('/login')
def login_page():
response = flask.make_response('login success')
# 设置cookie
response.set_cookie('user_id','10',max_age=50)
response.set_cookie('vip','0',max_age=50)
return response

@app.route('/logout')
def logout_page():
response = flask.make_response('logout success')
response.delete_cookie('user_id')
response.delete_cookie('vip')
return response

temp.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路由测试</title>
</head>
<body>
<h1>i am temp html</h1>
user_id = {{user_id}}
vip = {{vip}}
{% if vip == "0" %}
<h1>你没充钱</h1>
{% elif vip == "1" %}
<h1>lv1的内容</h1>
<% endif %>

</body>
</html>

访问http://127.0.0.1/login后获得cookie,访问http://127.0.0.1/a后可以看到登录信息,接着访问http://127.0.0.1/logout后cookie删除,再访问http://127.0.0.1/a后只能看见None


session交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from datatime import timedelta
from flask import session

@app.route('/a')
def a_page():
user_id = session['user_id']
vip = session['vip']
return flask.render_template('temp.html',user_id=user_id,cip=cip)

# 配置session都需要配置加密字符串
app.config['SECRET_KEY'] = "key123"
# 设置7天有效
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)

@app.route('/login')
def login_page():
response = flask.make_response('login success')
session['user_id'] = "20"
session['vip'] = "0"
return response

@app.route('/logout')
def logout_page():
# 第一种删除session方法
session.pop('user_id',None)
session.pop('vip',None)

# 第二种
session['user_id'] = False
session['vip'] = False

# 第三种
session.clear()
return 'logout success'

temp.html中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路由测试</title>
</head>
<body>
<h1>i am temp html</h1>
user_id = {{user_id}}
vip = {{vip}}
{% if vip == "0" %}
<h1>你没充钱</h1>
{% elif vip == "1" %}
<h1>lv1的内容</h1>
<% endif %>

</body>
</html>

访问http://127.0.0.1/login后服务端获得session,访问http://127.0.0.1/a后可以看到登录信息,接着访问http://127.0.0.1/logout后session删除,再访问http://127.0.0.1/a后只能看见报错信息


表单操作

1
2
3
4
5
6
7
8
9
10
11
@app.route('/test')
def test_page():
return flask.render_template('test.html')

@app.route('chuli',methods=['POST'])
def chuli():
# 与后端进行交互
if request.method == "POST":
username = request.form.get("uanme")
paassword = request.form.get("passwd")
print("用户名提交了"+username+"密码提交了"+password)

temp.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试1</title>
</head>
<body>

<form method="post" action="/chuli">
用户名:<input type="text" name="uname" /><br>
密码:<input type="password" name="passwd" /><br>
<input type="submit" value="点我提交" />
</form>

</body>
</html>

此时界面上就有表单了,可以通过表单进行POST请求了,输入用户名和密码后进入chuli.html


数据库操作

首先你得装个MySQL数据库,后略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@app.route('chuli',methods=['POST'])
def chuli():
if request.method == "POST":
username = request.form.get("uanme")
paassword = request.form.get("passwd")
print("用户名提交了"+username+"密码提交了"+password)

# 打开数据库
db = pymysql.connect(host="localhost",user="root",password="root",db="flasktest")
# 创建游标对象
cursor = db.cursor()
# sql语句
sql = "select * from students where age > 5"
# 执行sql语句
cursor.execute(sql)
# 确认
db.commit()
list1 = []
for i in range(5):
# 接受查询返回的内容
data = cursor.fetchone()
# 取出来的是元组
li = list(data)
list1.append(li)
# 可以查看查询出来的内容了
print(list1)
print(list1[1][2])
for temp in cursor.fetchall():
dict = {'name':temp[1],'pass':temp[2]}
list1.append(dict)
# 可以查询的更加具体
print(list1[1]['name'])
# 关闭数据库连接
db.close()
# 可以把查询出来的东西返回到前端,通过控制语句再进行更细致的服务
return flask.render_template("chuli.html",list1 = list1)

chuli.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>处理</title>
</head>
<body>
处理完毕
<hr>
{% for line in list1 %}
<li>{{line.name}}</li>
<li>{{line.pass}}</li>
{% endfor %}
</body>
</html>

chuli.html接受到POST的请求后print用户名和密码,然后后端查询数据库,再把查询出来的结果返回到前端

其他sql语句同理,记得防sql注入