flask工具书-搭建一个简单Web应用
作者:林水火
说明:文档配图懒得添加了, 可以看我的csdn上传的同名资源
网络框架是一种工具,用于快速和容易地开发Web应用程序。它提供了许多常见的功能,例如用户认证、管理面板、表单处理和文件上传等,避免了重复编写代码的麻烦。
Flask是一个轻量级的、简单易用的Python Web网络应用程序框架。
当用户向服务器请求一个网站时,服务器会将请求传递给Flask。Flask通过URL确定请求的具体内容,然后调用相应的视图函数进行处理。视图函数可以执行各种操作,例如查询数据库、修改数据等,最终生成响应并发送给用户的Web浏览器。
1.第一个WEB服务
在flask运行后,请不要关闭代码终端。以下是基础代码解释:
**app:**我们可以称呼变量app为一个“实例”或“对象”,它有专属的“方法”与“属性”,我们后续所做的一切都是对app这个对象进行修改。
**route:**该单词的中文含义为:路由,它的主要作用是将URL路径和函数关联起来,route方法的参数即URL网址的内容,每个路由后面一般都会跟一个函数。例如,当前路由中的(‘/’)代表根目录,用户在输入IP地址和端口号后,index函数的返回值就是访问服务器所见内容。
**if name == ‘main’😗*python文件通常有两种使用方法
①直接执行当前文件
②import到其他的 python 文件中,作为第三方库被调用
加入该语句后,直接运行该程序才可以启动web服务器,如果他人import当前文件,则服务器不会启动,但是其中的视图函数等内容可以被引用。
from flask import Flask #引入Flask包
app = Flask(__name__) #创建一个Web应用的实例app
@app.route('/') #设定路由
def index(): #当浏览器中的地址符合路由规则时,就会进入该函数
return 'Hello World'
if __name__ == '__main__': #启动Web服务器
app.run()
[外链图片转存中…(img-eUyvoTcs-1695969725031)]
可以在浏览器中打开"http://127.0.0.1:5000/"访问该程序生成的web页面。
Q:访问网页时,在URL的末尾,是否需要加斜杠呢?
A:在某些浏览器中,当URL末尾没有斜杠时,浏览器可能会补全斜杠再发送请求。例如,在浏览器中输入baidu.com,就会自动来到https://www.baidu.com/。因此,实际的URL末尾是需要斜杠的。
2.路由传递信息
2.1获取信息
同样是使用路由函数,将其路径从"/“改为”/hello/",就需要在URL的最后加上对应内容,<>这类括号是路由方法中特有的,我们后续会使用其他方法。
from flask import Flask
app = Flask(__name__)
@app.route('/hello/<name>')
def hello(name):
return 'Hello ' + name
@app.route('/user/<int:user_id>')
def get_user(user_id):
return 'User ID: ' + str(user_id)
@app.route('/content/<username>/<password>/')
def login(username, password):
return '用户名:' + username + '密码:' + password
if __name__ == '__main__':
app.run()
现在我们向浏览器的地址栏中输入http://localhost:5000/hello/lin,你将在页面上看到”Hello lin”的字样。URL路径中/hello/后面的参数被作为hello()函数的name参数传了进来。
[外链图片转存中…(img-ir537G5x-1695969725032)]
2.2简单应用
from flask import Flask# 从flask框架中导入Flask类
app = Flask(__name__)# 传入__name__初始化一个Flask实例
app.config['JSON_AS_ASCII']=False
books = ['三国演义', '水浒传', '西游记', '红楼梦']
@app.route('/book/<int:book_id>')
def book_detail(book_id):
if book_id < len(books):
return books[book_id]
else:
return "没有找到"
if __name__ == '__main__':
app.run()
这里我们调用传入的数据进行判断,注意路由的变化。
[外链图片转存中…(img-8V9XmNfZ-1695969725032)]
3.GET/POST传递信息
在@app.route()中可以传入一个关键字参数methods,来指定该路由支持的HTTP方法,可填写HTTP协议**中的两种常见请求方法:GET和POST,其他方法不做要求。
方法名 | 作用 | 使用说明 | 程序实现 |
---|---|---|---|
GET | 从服务器获得数据 | 将数据按照variable=value的形式,添加到URL后面,并使用“?”连接,变量之间使用“&”连接;例如baidu.com/s?wd=百度 | request.args.get(‘name’) |
POST | 向服务器传递数据 | 将表单中的数据放在form的数据体中,按照变量和值相对应的方式,传递到action所指向URL。 | request.form.get(‘name’) |
3.1GET
使用该程序,能像代码2.1一样从URL中获取数据,请你思考:这两种方式有何区别?
from flask import Flask,request
app = Flask(__name__)
@app.route('/',methods=['GET'])
def hello():
name=request.args.get("name") # 字符串name代表获取输入时的url中的该变量内容
return "Hello "+name
@app.route('/user',methods=['GET'])
def user():
name=request.args.get('name')
psd=request.args.get('psd')
return "用户名:" + name +"密码:" + psd
if __name__ == '__main__':
app.run()
[外链图片转存中…(img-oAcvSsI9-1695969725032)]
3.2POST
POST方法需要配合页面使用,这里我们使用了render_template函数,让初始页面指向一个html文件’index.html’,该文件已被存放于templates文件夹下,请勿重命名文件夹或HTML文件。
from flask import Flask,request,render_template
app = Flask(__name__)
@app.route('/')
def hello():
return render_template('index.html')
@app.route('/login',methods=['POST'])
def login():
name=request.form.get("name")
return "欢迎登录:" + name
if __name__ == '__main__':
app.run()
index.html中的内容
<form action="/login" method="post">
<p>用户名</p>
<p><input type="text" name="user" /></p>
<p><input type="submit" value="确定"/></p>
</form>
[外链图片转存中…(img-SdsGlvqx-1695969725033)]
使用post方法后,我们的url中不会显示任何用户输入的信息。
4.总结
数据传输方法 | 定义方法 | 特点 | 备注 |
---|---|---|---|
路由传递信息 | [外链图片转存中…(img-Pp1ljEBc-1695969725033)] | 在使用时访问对应路由 | 浏览即可 |
HTTP方法传递信息 | [外链图片转存中…(img-gtZKHcdB-1695969725033)] | GET方法会将数据存储于URL中传递 POST方法的常见特征是:网页中有可提交的表单 | 需了解用户在访问不同路由时,服务器返回的内容 |
5.其他知识
5.1 Html基础语法
**HTML是什么?**一种可以被浏览器渲染的文本。
**HTML有什么用?**它是我们平时看到网页的实际内容,文本经渲染后才成为了我们看到的表单、图片、页面特效等等。
**需要掌握多少?**简单浏览即可,不用会写,考试也不考HTML语法。
如想了解更多,可以访问教程
5.1.1HTML 标签
- HTML 标签是由尖括号包围的关键词,比如
- HTML 标签通常是成对出现的,比如
和
- 标签对中的第一个标签是开始标签,第二个标签是结束标签
5.1.2HTML结构
[外链图片转存中…(img-LgbaYRil-1695969725033)]
5.1.3 常用语法
超链接:href是hypertext reference的缩写,代表超文本引用。
<a href="http://www.baidu.com">任意文本</a>
在上面的代码中,’任意文本’是一段普通文本,'href’是该标签中的属性。
加载图像:图像标签包括和源属性Src,源属性(src)指 “source”。源属性的值是图像的 URL 地址。
定义图像的语法是:
<img src="url" >
URL 指存储图像的位置。如果名为 “pulpit.jpg” 的图像位于 www.runoob.com 的 images 目录中,那么其 URL 为 http://www.runoob.com/images/pulpit.jpg。也可以使用本地的路径。
换行:br是break的缩写
<br>
5.2 了解SQL
**为什么是“了解”?**第四章我们会进一步学习数据库,这里仅作简单了解。
**数据库是什么?**按照数据结构来组织、存储和管理数据的仓库。
SQL是什么? SQL是Structured Query Language(结构化查询语言)的缩写,是用于访问和处理数据库的标准的计算机语言,你会看到许多用于处理数据库的python库或数据库软件都叫sqlxxx xxxsql,就像python的编辑器叫pycharm、thonny一样。
**教材用的操作数据库的python库是什么?**sqlite3
[外链图片转存中…(img-kcgC378c-1695969725033)]
需要注意的是,“create table、insert into”都是sql语言,而不是python语言,因此我们需要使用特定的函数来执行这些sql语言。
什么是游标对象?
使用sqlite3库时,要想实现数据库操作,必须创建数据库对象如db,再针对该数据库对象创建游标对象cur,在数据库内进行读取。
可以将游标理解为一个柜子,每次只能选中一排柜子里的东西,那么就需要不断移动我们的指针,找到我们想要的的东西。
[外链图片转存中…(img-FUttk3y1-1695969725034)]
常见代码有哪些?
在python中操作数据库需要用到cur.execute语句,其作用就是将字符串看作SQL语句,并执行,其中的cur是我们定义的游标/指针对象。
cur.execute("INSERT INTO tp(地址,学号) VALUES('%s','%s')" %(ip,'0'))
例如上方的代码,就是向数据表tp
的地址和学号列插入(insetr
)了数据
一些重要的 SQL 命令
SELECT - 从数据库中提取数据
UPDATE - 更新数据库中的数据
DELETE - 从数据库中删除数据
INSERT INTO - 向数据库中插入新数据
CREATE DATABASE - 创建新数据库
CREATE TABLE - 创建新表
DROP TABLE - 删除表
6.拓展1_Jinja2模板
[外链图片转存中…(img-LTpPIwqB-1695969725034)]
网页模板是什么?:在案例3.2中,我们已经调用过了render_template函数读取特定目录下的html文件,这就是模板的调用。我们在渲染一个网页的时候,并不是只渲染一个纯文本字符串,而是需要渲染一个内容复杂的html文档。
html文件能自动生成吗?:例如,根据本次读取的学生名单,用代码循环生成班级人数个的投票选择框。为了解决这一任务,我们就提出了这样的需求:根据flask中的代码,自动调整html页面中的内容。
**如何实现?:**Jinja2是一个模板引擎,它是Flask框架的默认模板引擎,了解其语法规范,分别在python代码和html代码中进行对应修改,就可以满足我们刚才提出的需求。
**这个名字是什么意思?:**template模板 /ˈtempleɪt/ temple 寺庙 /ˈtempl/
其命名与日本的神社有些相似之处,这么看来,这个库的名字还曾有机会成为Miao的。
6.1基础模板
from flask import Flask #引入Flask包
app = Flask(__name__) #创建一个Web应用的实例app
@app.route('/') #指明地址是根路径
def index(): #当请求的地址符合路由规则时,就会进入该函数。
return render_template('index.html')
if __name__ == '__main__': #启动Web服务器
app.run()
在该代码目录下,创建一个子目录”templates”(注意,一定要使用这个名字)。然后在”templates”目录 下创建文件”index.html”。
<h1>欢迎您</h1>
以上代码调用了另一个文件。
6.2Jinja2模板调用
在上述除3.2的代码中,flask完成了两个任务:①处理数据②展示信息,flask能够将这两个任务分离,在路由函数中专注于处理具体任务,而信息的展示则交由Jinja2模板引擎完成。在该模板中,有一些特殊的语法**(浏览即可,无需记住)**。
{{ … }}:用来装载一个变量,模板渲染的时候,会把这个变量代表的值替换掉。并且可以间接访问一个变量的属性或者一个字典的key。访问字典对象的值时,就行DataFrame对象一样,点号访问和[]中括号。
{% … %}:所有的控制语句都是放在{% … %}中,并且有一个语句{% endxxx %}来进行结束,Jinja中常用的控制语句有if/for…in.
{# … #}:用来装载一个注释,模板渲染的时候会忽视这中间的值。
例如,下方代码对比4.1,仅在render_template函数中添加了变量,就能完成信息的传递(user为html中提前定义好的变量名)。
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html',name = 'lin')
if __name__ == '__main__':
app.run()
html内容
<h1>欢迎您{{name}}</h1>
运行结果:
[外链图片转存中…(img-AP5E0IAq-1695969725034)]
7.拓展2_表单
HTML中的form表单提供了交互控制元件,用于收集用户输入的内容,向Web服务器提交信息。
格式(缩进不影响效果):
<form>
<p>表单中的内容,如果没有input属性那就只是一段普通文本</p>
</form>>
关键属性:
action:提交表单时执行的动作,通常表单会被提交到web服务器上的某个网页。
method:提交表单时所用的HTTP方法(GET或者POST)
[外链图片转存中…(img-V9drVwdi-1695969725034)]
其中的input类型有多种可选类型,如Text文本、Check复选框、Radio单选按钮、Select 下拉列表、File选取文件、Submit and Reset Button提交或者重置按钮控件。上方html代码经浏览器渲染后如下所示
姓名:
性别:男 女
7.1Flask处理通用表单(在html中书写静态表单)
web服务器代码:当请求路径为http://127.0.0.1:5000/时,render_template()函数呈现templates文件夹内index.html的内容,按下提交按钮时即提交表单数据,执行action动作,表单数据提交到http://127.0.0.1:5000/success,根据不同http方法,执行不同分支,页面呈现不同内容。
from flask import Flask,render_template,request
app = Flask(__name__)
@app.route('/')
def index():
return render_template("index.html")
@app.route('/success', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return "响应 GET 请求,提交表单数据成功!"
else:
return "响应 POST 请求,提交表单数据成功!"
if __name__ == "__main__":
app.run(debug=True)
index.html内容:
<p>GET方法提交表单数据</p>
<form action="/success" method="get">
<p>姓名:<input type="text" name="name"></p>
<p>性别:<input type="radio" name="sex" value="male" checked>男
<input type="radio" name="sex" value="female">女</p>
<p><input type="submit" value="提交"> </p>
</form>
<p>POST方法提交表单数据</p>
<form action="/success" method="post">
<p>姓名:<input type="text" name="name"></p>
<p>性别:<input type="radio" name="sex" value="male" checked>男
<input type="radio" name="sex" value="female">女</p>
<p><input type="submit" value="提交"> </p>
</form>
GET方法提交表单效果:
[外链图片转存中…(img-ZktxWOSS-1695969725035)]
POST方法提交表单数据效果:
[外链图片转存中…(img-v7Ih1XYT-1695969725035)]
何时使用GET?何时使用POST?
如果表单提交是被动的(比如搜索引擎查询),提交数据量较少且没有敏感信息,可以选择使用 GET ,注意:有表单也可以使用get方式提交,此时表单数据在页面地址栏中是可见的。
如果表单数据需要更新,或者包含敏感信息(例如密码),POST 的安全性更好,在页面地址栏中被提交的数据是不可见的。
7.2Flask_wtf的使用(html接收来自代码的动态表单)
WTForms是一个灵活的表单,渲染和验证库。 使用Flask-WTF,可以在Python脚本中定义表单域并使用HTML模板来呈现它们, 也可以将验证应用于WTF字段。
为什么使用flask_wtf?
- 方便动态呈现表单元素。
- HTML本身无法验证用户的输入,使用该拓展可以对输入内容进行验证。
首先,需要安装flask_wtf拓展。
pip install flask_wtf
flask_wtf内置标准表单字段
字段 | 描述 |
---|---|
StringField | 单行文本输入框 |
TextField | 单行文本输入框 |
BooleanField | 多选框 |
RadioField | 单选框 |
SelectField | 下拉列表框 |
TextAreaField | 多行长文本输入框 |
PasswordField | 密码输入框(输入内容自动变为*) |
SubmitField | 提交按钮 |
例如,我们想要实现一个登录的网页表单,包含一个文本输入框,一个密码输入框和一个提交按钮。
Python定义一个表单类:
from flask_wtf import FlaskForm #导入表单模块
from wtforms import StringField,PasswordField,SubmitField #导入表单相关模块
Class LoginForm(FlaskForm): #设置网页表单类
name=StringField("用户名:") #字符输入框
password=PasswordField("密码:") #密码输入框
submit=SubmitField("登录") #提交按钮
表单类实例化
form = LoginForm()
渲染时,等效html脚本如下:
<form>
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="password"></p>
<p><input type="submit" value="登录"></p>
</form>
web服务器完整代码:
from flask import Flask,render_template,request #导入flask模块
from flask_wtf import FlaskForm #导入表单模块
from wtforms import StringField,PasswordField,SubmitField #导入表单相关模块
app=Flask(__name__)
app.config["SECRET_KEY"]="hard_to_guess_string" #启动配置,设置密钥,表单内容通过加密传输
class LoginForm(FlaskForm): #设置网页表单类
name=StringField("用户名:") #字符输入框
password=PasswordField("密码:") #密码输入框
submit=SubmitField("登录") #提交按钮
@app.route('/', methods=['GET', 'POST'])
def index():
form = LoginForm() #表单类实例化
if request.method=="POST": #收到POST消息
if form.name.data==form.password.data: #自定义验证条件,使用户名、密码符合验证条件
return render_template("text.html", s=form.name.data)
#登录成功,往新页面传入用户名s
else:
return render_template("load.html",form=form)
#登录失败,回到本页面
else:
return render_template("load.html",form=form)
if __name__=="__main__":
app.run(debug=True)
注意:代码中使用 request.method == 'POST’接受按键按下后表单的返回值。课本上采用的是form.validate_on_submit()检测按键按下事件,两者效果基本等价。
load.html内容:
<html>
<body>
<h1>Load Form
<form method="post">
<p>{{form.name.label}} {{form.name}}</p>
<p>{{form.password.label}} {{form.password}}</p>
<p>{{form.submit}}</p>
</form>
</body>
</html>
text.html内容:
<html>
<body>
<h1>登录成功!<h1>
{% if s=="admin"%}
<h1>Hello,Boss!</h1>
{%else%}
<h1>Hello,{{s}}!</h1>
{%endif%}
</body>
</html>
浏览器登录页面(load.html)
表单中输入用户名为admin的效果(text.html):
表单中输入用户名为bob的效果(text.html):