打开终端可以看出使用的是p1的虚拟机终端了
在flask种输入一个完整并且存在的函数名称或者类明, 然后 Alt + 回车,pycharm可以自动导包,不用在手动在代码头部导入包
(p1) E:\code\p1>pip install flask
pip list:查看所有的安装包
pip feeze 查看自己安装包
(p1) E:\code\p1>pip freeze
blinker==1.7.0
click==8.1.7
colorama==0.4.6
Flask==3.0.0 #这里安装的是3.0.0版本
importlib-metadata==7.0.1
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.3
Werkzeug==3.0.1
zipp==3.17.0
创建app.py文件
from flask import Flask
#创建Flask对象
app = Flask(__name__)
# 路由 + 视图函数, 其中 / 就是用户访问的url,hello就是视图函数
@app.route('/')
def hello():
#返回给浏览器的数据
return 'hello'
if __name__ == "__main__":
#启动flask
app.run()
app.run(debug=True,port=5000,host='0.0.0.0')
debug是开启调试模式,每次修改完代码之后不用重启flask
因为flask所有的路由和视图函数都写在了app文件中,一旦逻辑复杂起来,函数多起来,阅读性就非常差,这就需要把项目差分开。这里就使用到了 “蓝图”。蓝图主要是是对 路由 进行了重新规划。
官方推荐了两种蓝图模式,这里只写一种。
其原理就是把所有的视图函数文件、静态文件、模板文件都放在一个"包"中。然后将不通类型的视图函数 分开编写
app.py #启动文件
apps #这可是一个 自定义的python包
__init__.py #包的初始化文件
static #存放静态文件的目录
templates #存放模板文件的目录
views #存放视图函数目录
v1.py #视图函数1
v2.py #视图函数2
因为包的初始话文件,在其它文件导入的时候会自动执行,所有把创建flask的语句写在这里
from flask import Flask
#导入两个蓝图
from .views.v1 import blue_login
from .views.v2 import blue_home
def create_app():
app = Flask(__name__)
#将app实例与两个蓝图绑定
app.register_blueprint(blue_login)
app.register_blueprint(blue_home)
return app
编辑v1.py
from flask import Blueprint
#创建一个蓝图,login为自定义的"蓝图"名称
blue_login = Blueprint("login",__name__)
@blue_login.route('/login')
def login():
return '用户登录
'
编辑v2.py
from flask import Blueprint
blue_home = Blueprint("home",__name__)
@blue_home.route('/home')
def home():
return '用户首页
'
from apps import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
启动flask,分别访问这两个函数,就可以看到结果了
http://127.0.0.1:5000/home
http://127.0.0.1:5000/login
有时候需要获取url中的参数,这时候就用到了 flask中的路由参数功能
from flask import Flask
app = Flask(__name__)
#username是一个string的变量,用户输入的url会赋值给username
@app.route('/' )
def login(username):
return username
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
flask支持的类型有以下几种:
string
int #int 类型注意,flask是不能直接返回int类型的
float
path
any
uuid
path类型,如果用户输入得到是多级url 比如: /xx/xx/xx/x/ 都会获取到
from flask import Flask
app = Flask(__name__)
@app.route('/' )
def login(username):
return username
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
用户请求多级目录 都会被获取到
http://127.0.0.1:5000/zhangsan/login/aaa
用户请求的路径必须在指定的值当中,如果不在就报错.当用户输入的是除zhangsan lisi以外的内容就会报错
@app.route('/' )
def login(username):
return username
限制用户使用请求方法
from flask import Flask
app = Flask(__name__)
@app.route('/',methods=['GET','POST'])
def login():
return '首页'
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
请求相关的属性
url :完整的请求地址
base_url: 去掉get参数的url
host_url: 只有主机和端口号的url
path: 路由中的路径
method: 请求方法
remote_addr: 请求的客户端地址
args: get请求参数
form: post请求参数
files: 文件上传
headers 请求头
cookies: 请求中的cookie
打印参数
#这里要导入flask的request对象
from flask import Flask,request
app = Flask(__name__)
@app.route('/login',methods=['GET','POST'])
def login():
print("url = {}".format(request.url))
print("base_url = {}".format(request.base_url))
print("host_url = {}".format(request.host_url))
print("path = {}".format(request.path))
print("method = {}".format(request.method))
return '首页'
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
在浏览器访问:
http://127.0.0.1:5000/login?user=zhangsan&password=123
结果如下
url = http://127.0.0.1:5000/login?user=zhangsan&password=123
base_url = http://127.0.0.1:5000/login
host_url = http://127.0.0.1:5000/
path = /login
method = GET
from flask import Flask,request
app = Flask(__name__)
@app.route('/login',methods=['GET','POST'])
def login():
#这里只打印用户传递过来的参数
print("args = {}".format(request.args))
return '首页'
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
浏览器访问
http://127.0.0.1:5000/login?user=zhangsan&password=123
打印结果如下:
args = ImmutableMultiDict([('user', 'zhangsan'), ('password', '123')])
ImmutableMultiDict这种类型叫做 “类对象”,获取类对象中的值方法有3种,如下:
三种方法的区别在于:
request.args[] 这种形式如果key不存在就会报错
request.args.get() 这种形式如果key不存在不会报错,会返回none,所以这种用的比较多
request.args.getlist() 如果args种 有重复的key,这种形式会将所有key都取出来,上边两种只会取第一个
from flask import Flask,request
app = Flask(__name__)
@app.route('/login',methods=['GET','POST'])
def login():
print("args = {}".format(request.args))
print(request.args['user'])
print(request.args.get('user'))
print(request.args.getlist('password'))
return '首页'
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
结果如下:
args = ImmutableMultiDict([('user', 'zhangsan'), ('password', '123')])
zhangsan
zhangsan
['123']
flask接受post请求使用的是 request.form。
from flask import Flask,request,jsonify
app = Flask(__name__)
@app.route('/login',methods=['GET','POST'])
def login():
print('post请求={}'.format(request.form.get('user')))
return '首页'
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
使用postman 请求, post的数据需要使用"form-data"类型进行提交。 如果使用json格式进行提交,flask需要使用 request.json进行接收。
返回的数据一般有以下几种
return "字符串"
这种使用的是前后端不分离的情况
#需要导入render_template
from flask import render_template
return render_template('index.html')
然后在templates目录下编写index.html
这种情况使用的是前后端分离的情况
return jsonify(python字典)
def login():
html = render_template('index.html',name="zhangsan")
res = Response(html)
return res
flask中重定向有两种用法
第一种:
from flask import Flask,redirect
app = Flask(__name__)
@app.route('/',methods=['GET','POST'])
def index():
#如果用户访问根,直接跳转到 login路由
return redirect('/login')
@app.route('/login',methods=['GET','POST'])
def login():
return "登录页面"
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
第二种
url_for.以下这种方式也叫做 反向解析,通过函数名找url
res = url_for('蓝图名称.视图函数名称')
return redirect(res)
cookie是客户端的会话技术
cookie的作用:让服务器能够分判出 不同的http请求。应用场景一般用于登录。
产生cookie的过程:
1.用户携带用户名和密码进行登录
2.服务端验证用户名和密码,然后设置好cookie,和用户名和密码绑定,返回给浏览器
3.浏览器会自动保存cookie到本地
4.浏览器下次在请求的时,会自动带上cookie
5.取出cookie的值,判别哪个用户在访问,返回对应用户的数据
1.设置cookie
response.set_cookie(key,value[,max_age=None,exprise=None])
max_age: 整数,指定cookie的过期时间,单位为秒
expries: 整数,指定过期时间,可以指定一个具体日期时间
以上两个参数选择一个指定即可
2.获取cookie
request.cookies.get(key)
3.删除cookie
response.delete_cookie(key)
此目录存放html文件,此目录下创建login.html,home.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>logintitle>
head>
<body>
<form action="/login" method="post">
<h1>登陆页面h1>
用户名:<input type="text" name="username" id=""><br>
密 码:<input type="password" name="password" id=""><br><br>
<button type="submit">提交按钮button>
form>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hometitle>
head>
<body>
<h1>Home页面h1>
body>
html>
解释:max
from flask import Flask,render_template,request,Response,redirect
app = Flask(__name__)
@app.route("/")
@app.route('/login',methods=["GET","POST"])
def login():
if request.method == "GET":
return render_template("login.html")
elif request.method == "POST":
username = request.form.get("username")
passworwd = request.form.get("password")
if username == "admin" and passworwd == "admin":
getCookie = request.cookies.get("testcookie")
if getCookie:
return redirect("/home")
else:
res = redirect("/home")
res.set_cookie("testcookie","2024",max_age=10)
return res
else:
return "用户名或者密码错误"
@app.route("/home")
def home():
getCookie = request.cookies.get("testcookie")
if getCookie == "2024":
return render_template("home.html")
else:
return redirect("/login")
if __name__ == "__main__":
app.run(debug=True,host="0.0.0.0")
解释: cookie的过期时间为10秒,过期后,浏览器会自动删除cookie
session是服务器端的会话技术,依赖于cookie
特点:
服务端的会话技术
所有数据存在服务器中
默认存储在内存中
存储结果也是key-value的形式
session 是离不开cookie
flask中的seesion是全局对象
设置session
session['key'] = 'value'
获取session
session.get(key,default=NOne)
删除session
session.pop(key)删除某一值
session.clear() 清楚所有
cookie:
1.在浏览器存储
2.安全性较低
3.可以减轻服务器压力
session:
1.在服务器存储
2.安全性高
3.对服务器要求较高
4.依赖cookie
在home.html中增加 退出
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>home</title>
</head>
<body>
<h1>Home页面</h1>
<form action="logout" method="post">
<button type="submit">注销</button>
</form>
</body>
</html>
from flask import Flask,render_template,request,Response,redirect,session
import datetime
app = Flask(__name__)
#设置一个安全的密钥,否则无法成功返回session
app.secret_key = "abc123"
#为了测试设置session的过期时间为3秒,session过期后不会自动删除sessIon
app.permanent_session_lifetime = datetime.timedelta(seconds=3)
@app.route("/")
@app.route('/login',methods=["GET","POST"])
def login():
if request.method == "GET":
return render_template("login.html")
elif request.method == "POST":
username = request.form.get("username")
passworwd = request.form.get("password")
if username == "admin" and passworwd == "admin":
getCookie = session.get("testcookie")
if getCookie:
return redirect("/home")
else:
res = redirect("/home")
session["testcookie"] = "2024"
return res
else:
return "用户名或者密码错误"
@app.route("/home")
def home():
getCookie = session.get("testcookie")
if getCookie == "2024":
return render_template("home.html")
else:
return redirect("/login")
@app.route("/logout",methods=["POST"])
def logout():
session.pop('testcookie')
return redirect("/login")
if __name__ == "__main__":
app.run(debug=True,host="0.0.0.0")
[root@node-2 templates]# cat index.html
<h1>
<form action="/upload" method="post" enctype="multipart/form-data">
#这里的 name的值决定了 flask 获取上传文件的key
<input type="file" id="fileInput" name="file">
<br><br>
<input type="submit" value="提交">
form>
h1>
from flask import Flask,render_template,request
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/upload",methods=["GET","POST"])
def upload():
print(request.files)
print(request.files.get('file'))
print(request.files.get('file').filename)
return "upload OK!!!
if __name__ == "__main__":
app.run(debug=True,host='0.0.0.0')
上传一张图片,查看日志
打印结果如下:
ImmutableMultiDict([('file', <FileStorage: '1.jpeg' ('image/jpeg')>)])
<FileStorage: '1.jpeg' ('image/jpeg')>
1.jpeg
request.files的值为
ImmutableMultiDict([('file', <FileStorage: '2.jpeg' ('image/jpeg')>)])
这里的file 就是 html中 input 中的name的值
request.file.get(‘file’) 的值为:
<FileStorage: '2.jpeg' ('image/jpeg')>
这个值就是要存储的对象
request.file.get(‘file’).filename 的值
1.jpeg
from flask import Flask,render_template,request
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/upload",methods=["GET","POST"])
def upload():
save_url = "/root/python"
files = request.files.get('file')
if files:
file_name = files.filename
files.save("{}/{}".format(save_url,file_name))
return "upload OK!!!"
else:
return "上传文件不能为空!"
if __name__ == "__main__":
app.run(debug=True,host='0.0.0.0')
Flask中使用Jinja2模板引擎
Jinja2是由Flask作者开发。
模板优势:
速度快,被广泛应用
HTML设计和后端python分离
减少python复杂度
非常灵活,快速和安全
提供了控制,继承等高级功能
在pycharm中写html 输入任意标签 按tab键自动补齐标签。
模板语法主要有两种:
变量 和 标签
语法: {{ 变量名 }}
视图传递给模板的数据
变量如果不存在,默认忽略
语法: {% 标签 %}|
这个标签可以是 控制逻辑,外部表表达式,创建变量、宏定义
视图函数中传递变量
return render_template('login.html',username=”zhangsan“)
html中引入变量
<p>姓名: {{ username }}p>
视图中定义变量,并返回
def login():
data = {
"user": "zhangsan",
"age": 20,
"likes": ["乒乓球","游泳","听音乐"]
}
return render_template('login.html',**data)
html中引入传入的data的值
<body>
<h1>登录首页h1>
<p>姓名: {{ user }}p>
<p>年龄: {{ age }}p>
<p>爱好: {{ likes[0] }}p>
body>
姓名: {{ user }}
{% if age > 18 %}
年龄:成年人
{% else %}
年龄:未成年
{% endif %}
爱好: {{ likes[0] }}
其中 loop.index0 写法是固定的。
爱好
{% for i in likes %}
{{ i }}
索引: {{ loop.index0 }}
{% endfor %}