flask框架学习
以前只整过js的后端,这次网安平台实践大作业打算用python写后端,于是赶紧滚过来学学flask
简介与安装
Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。
Flask是目前十分流行的web框架,采用Python编程语言来实现相关功能。Flask框架的主要特征是核心构成比较简单,但具有很强的扩展性和兼容性,程序员可以使用Python语言快速实现一个网站或Web服务。一般情况下,它不会指定数据库和模板引擎等对象,用户可以根据需要自己选择各种数据库。
安装直接pip install flask
就行,如果害怕环境乱了,建议用anaconda或者virtualenv
我win下的环境已经乱的可以了,懒得搞了(
安装完成后可以用python运行下面的代码试试
from flask import Flask
app = Flask(__name__) # Flask函数接收参数__name__,指向了程序所在的包,即Flask将在当前模块运行
@app.route("/") # route()是一个装饰器,它会进行路由匹配,将请求的url映射到函数上。这里'/'与hello_world进行了绑定
def hello_world():
return "Hello, World!"
if __name__ == '__main__':
app.run() # run方法启动了web服务器,默认是127.0.0.1:5000
能看到这个页面就安装胜利了
顺便讲一下上面代码中的run(),其参数是app.run(host, port, debug, options)
- host是将要监听的域名,默认为localhost(127.0.0.1),设置为0.0.0.0就可以在外部服务器使用
- port是监听的端口,默认5000
- debug是提供调试信息,默认为false
- options是要转发到底层的Werkzeug服务器.
需要注意的一点,根据官方文档,尽管交互式调试器在允许 fork 的环境中无法正常使用(也即在生产服务器上正常使用几乎是不可能的),但它依然允许执行任意代码。这使它成为一 个巨大的安全隐患,因此它绝对不能用于生产环境 。
路由
Flask中的路由是指用户请求的URL与视图函数之间的映射,现代Web框架使用路由技术来帮助用户记住应用程序URL,可以直接访问所需的页面,而无需从主页导航。
@app.route('/hello')
def hello_world():
return "Hello, World!"
这里,URL '/hello' 规则绑定到了hello_world()
,如果用户访问localhost:5000/hello,则hello_world()
的输出将在浏览器中体现
另外,application对象的add_url_rule()
也可将URL与函数绑定
def hello_world():
return "Hello, World!"
app.add_url_rule('/', 'hello', hello_world)
基础语法
向规则参数添加变量,可以动态构建URL,变量记为<variable_name>
举个例子
from flask import Flask
app = Flask(__name__)
@app.route("/hello/<name>")
def hello_world(name):
return "Hello, %s" % name
app.run()
route()
的URL里加入了/<name>,并且我们将参数附加到了hello_world()
函数内
看一下效果
大概来说这个<name>可以被动态替换,你输入的url是什么他就是什么
这个<name>是字符串替换,还有其他的替换类型
- int:整数替换
- float:浮点值替换
- path:可接受用作目录分隔符的斜杠
from flask import Flask
app = Flask(__name__)
@app.route("/test/<int:var_a>")
def test_1(var_a):
return "Number is: %d" % var_a
@app.route("/tset/<float:var_b>")
def test_2(var_b):
return "Float is: %f" % var_b
app.run()
看看效果呢
而且float不能接受整数
直接not found了
另外,Flask的URL规则基于Werkzeug的路由模块,这确保形成的URL是唯一的,并且基于Apache规定的先例。
看看这个
from flask import Flask
app = Flask(__name__)
@app.route("/test_1")
def test_1():
return "Can You See Me?"
@app.route("/test_2/")
def test_2():
return "Can You See Me?"
app.run()
注意这个'/',在源码中第二个参数是/test_2/
,这让他成为了一个规范的URL,所以访问/test_2和/test_2/都合法。但是/test_1/就不行了,因为他的参数是/test_1
另外,在url构建中,url_for()
也十分有用。
url_for()
的第一个参数为函数名,后续参数为多个关键字参数,每个参数对应URL的变量部分
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/admin')
def Admin():
return 'Admin Access'
@app.route('/guest/<guest>')
def Guest(guest):
return 'Guest %s Access' % guest
@app.route('/user/<name>')
def User(name):
if name == 'admin':
return redirect(url_for('Admin'))
else:
return redirect(url_for('Guest', guest = name))
app.run()
与url_for()
有关的是user()
,他检查了<name>是否为'admin'
若匹配成功,则使用url_for()
重定位至函数Admin()
,否则重定位至函数Guest()
,并且将接收的参数name传递给Guest()
作为他的参数
在访问http://127.0.0.1:5000/user/admin后,发现其重定位至http://127.0.0.1:5000/admin
然后其他的参数就会重定位到guest界面
在http中有不同的从URL检索数据的方法
- GET: 以未加密的形式将数据发送到服务器
- HEAD: 和GET方法相同,但没有响应体
- POST: 用于将HTML表单数据发送到服务器,并且POST方法接收的数据不由服务器缓存
- PUT: 用上传的内容替换目标资源的所有当前表示
- DELETE: 删除由URL给出的目标资源的所有当前表示
在Flask中,路由一般响应GET请求,但我们可以通过route()
来改变他
我们尝试更改为响应POST请求,先写一个html表单,保存为test.html
<html>
<body>
<form action = "http://localhost:5000/login" method = "post">
<p> Enter Name: </p>
<p> <input type = "text" name = "username" /> </p>
<p> <input type = "submit" value = "submit" /> </p>
</form>
</body>
</html>
然后写一下Flask
from flask import Flask, redirect, url_for, request, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template("test.html")
@app.route('/success/<name>')
def success(name):
return 'welcome, %s' % name
@app.route('/login', methods = ['POST', 'GET'])
def login():
if request.method == 'POST':
print("Method is POST")
user = request.form['username']
return redirect(url_for('success', name = user))
else:
print("Method is GET")
user = request.args.get('username')
return redirect(url_for('success', name = user))
app.run()
render_template()
可以渲染一个静态的html文件,并且实现参数的传递。他会自动在templates文件夹中找到对应的html,因此我们不需要给出html的完整路径。
我们打开test.html,并且随便写点东西进去
表单数据将POST到表单标签的action子句中的URL
/login映射到login()
,通过user = request.form['username']
来获取POST方法传递的数据,此处获得了参数username的值
他将作为变量传递给success()
,并转到相应的URL,打印相应的文字。
同时,我们可以看到
测试语句的输出表明确实是POST方法而非GET方法
若我们将html中的方法改为GET,则会通过user = request.args.get('username')
来获取数据。args和其他语言差不多,是包含表单参数对及其对应值对的列表的字典对象
和数据库有关的操作
数据库选用SQLite,直接来一个实例吧。实例目标是创建一个学生表
先创建一个SQLite数据库database.db
import sqlite3
conn = sqlite3.connect('database.db')
conn.execute('CREATE TABLE students (name TEXT, addr TEXT, city TEXT, pin TEXT)')
conn.close()
第一个函数new_student()
@app.route('/new_student')
def new_student():
return render_template('student.html')
对应的student.html如下
<html>
<body>
<form action = "{{ url_for('addrec') }}" method = "POST">
<h3> Student Information </h3>
Name <br>
<input type = "text" name = "name" /> </br>
Address <br>
<textarea name = "add" > </textarea> <br>
City <br>
<input type = "text" name = "city" /> <br>
PINCODE <br>
<input type = "text" name = "pin" /> <br>
<input type = "submit" value = "submit" /> <br>
</form>
</body>
</html>
第二个函数add()
函数通过POST检索表单数据,插入到学生表中,操作的成功以及失败信息均显示在result.html中
@app.route('/add', methods=['POST', 'GET'])
def add():
if request.method == 'POST':
try:
name = request.form['name']
addr = request.form['add']
city = request.form['city']
pin = request.form['pin']
with sql.connect("database.db") as con:
cur = con.cursor()
cur.execute("INSERT INTO students (name, addr, city, pin) VALUES(?, ?, ?, ?)", (name, addr, city, pin))
con.commit()
msg = "Successfully Recorded"
except:
con.rollback()
msg = "Error While Inserting"
finally:
return render_template("result.html", msg = msg)
con.close()
result.html中仅包含一个转义语句,用来显示操作结果
<html>
<body>
result of addition : {{ msg }}
<h2> <a href = "\"> go back to home page </a> </h2>
</body>
</html>
第三个函数list()
将填充的对象传递给list.html
@app.route('/list')
def list():
con = sql.connect("database.db")
con.row_factory = sql.Row
cur = con.cursor()
cur.execute("select * from students")
rows = cur.fetchall()
return render_template("list.html", rows = rows)
list.html比较模板,遍历并打印数据
<html>
<body>
<table border = 1>
<thead>
<td> Name </td>
<td> Address </td>
<td> city </td>
<td> Pincode </td>
</thead>
{% for row in rows %}
<tr>
<td> {{row["name"]}} </td>
<td> {{row["addr"]}} </td>
<td> {{ row["city"]}} </td>
<td> {{row['pin']}} </td>
</tr>
{% endfor %}
</table>
<a href = "/"> Go back to home page </a>
</body>
</html>
最后也是最初的函数home()
,呈现home.html作为入口点
@app.route('/')
def home():
return render_template('home.html')
home.html比较简单
<html>
<body>
<a href = "/new_student"> Add New Record </a>
<br/>
<a href = "/list"> Show List </a>
</body>
</html>
运行源码,访问http://localhost:5000/,就能玩一下这个简单的学生表操作了