Flask:初识
1 Flask介绍(轻量级的框架,非常快速的就能把程序搭建起来)
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。
“微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。
默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。
和django的比较
django:无socket,依赖第三方模块wsgi,中间件,路由系统(CBV,FBV),视图函数,ORM。cookie,session,Admin,Form,Auth,缓存,信号,序列化。
Flask:无socket,中间件(扩展),路由系统,视图(CBV)、第三方模块(依赖jinja2),cookie,session弱爆了
2 简单使用
2.1 安装
pip3 install flask
2.2 Werkzeug 简介
Werkzeug 是一个WSGI工具包,它可以作为一个web框架的底层库,它封装了很多web框架的东西,如Request,Response
#Flask依赖一个实现wsgi协议的模块:werkzeug
from werkzeug.wrappers import Request, Response
@Request.application
def hello(request):
return Response('Hello World!')
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, hello)
2.3 flask快速使用
from flask import Flask
app = Flask(__name__) # 实例化产生一个Flask对象
# 将'/'路径和视图函数index的对应关系添加到路由中
# 装饰器加括号执行route,返回decorator函数内存地址,把index当做参数传给decorator函数执行
@app.route('/')
def index():
return 'Hello World!'
if __name__ == '__main__':
# 不传参默认loaclhost, 5000端口
# 最终调用的run_simple(),把Flask对象app传过去
# werkzeug会执行app(),并传入request对象,执行app()--》触发Flask类的__call__方法
app.run()
2.4 web框架三板斧
1 返回字符串类型的数据
# django用法:return HttpResponse('hello i am djanggo')
# flask用法: return 'hello i am flask' 直接返回字符串
2 返回html文件,即返回html渲染的页面
# django用法:return render(request, 'djangohtml.html')
# flask用法: return render_template('flask.html')
# 生成Flask对象时,初始化默认template_folder='templates',因此在根路径下建一个templates文件夹,存放html模板
# 模板语法传值
# django用法: return render(request, 'render_html.html',{'data': user_dict,'data2':123})
# return render(request, 'render_html.html',locals())
# flask用法: return render_template('flask.html',data=user_dict,data2='egon') 直接key=val传值,不用字典
3 重定向
# django用法: return redirect('/home/') 可以跳转到其他url或自定义的路由
# redirect括号内可以直接写url,也可以直接写别名;但redirect只能反向解析不带参数的,如果别名需要额外传参,就必须使用reverse
# flask用法: return redirect('http://taobao.com/')
2.5 两种添加路由的方式
方式一:
@app.route('/index') # @decorator
def index():
return "Index"
方式二:
def index():
return "Index"
# 路由的本质,endpoint是别名,如果不写,就用视图函数名作为别名;endpoint不能重名
app.add_url_rule('/index', view_func=index, endpoint='nl')
2.6 Flask中装饰器应用
from flask import Flask,render_template,request,redirect,session
app = Flask(__name__)
app.secret_key = "sdsfdsgdfgdfgfh"
# 登录认证装饰器
def wrapper(func):
def inner(*args,**kwargs):
if not session.get("user_info"):
return redirect("/login")
ret = func(*args,**kwargs)
return ret
return inner
@app.route("/login",methods=["GET","POST"])
def login():
if request.method=="GET":
return render_template("login.html")
else:
# print(request.values) #这个里面什么都有,相当于body
user = request.form.get("user")
pwd= request.form.get("pwd")
if user=="zl" and pwd="123":
session["user_info"] = user
# session.pop("user_info") #删除session
return redirect("/index")
else:
# return render_template("login.html",**{"msg":"用户名或密码错误"})
return render_template("login.html",msg="用户名或者密码错误")
# 装饰器执行顺序从上至下,匹配路由后才能进行认证
@app.route("/index",methods=["GET","POST"])
@wrapper
def index():
# if not session.get("user_info"):
# return redirect("/login")
return render_template("index.html")
if __name__ == '__main__':
app.run(debug=True)
2.7 请求响应相关
# request
- request.form #POST请求
- request.args #GET请求,字典形式的
- request.querystring #GET请求,bytes形式的
# response
- return render_tempalte()
- return redirect()
- return ""
v = make_response(返回值) #把返回的值包在了这个函数里面
# session
- 存储在浏览器上(django的session默认存在数据库django_session表中),并且是加密的
- 依赖于:secret_key
- 设置:session['username'] = 'xxx'
- 删除:session.pop('username', None)
案例:登录,显示用户信息
View Code
from flask import Flask, render_template, request, redirect, session, url_for
app = Flask(__name__)
app.debug = True
app.secret_key = "sdsfdsgdfgdfgfh" # 跟django的settings中的密钥一个意思,设置session的加密方式
USERS = {
1: {'name': '张三', 'age': 18, 'gender': '男', 'text': '道路千万条'},
2: {'name': '李四', 'age': 28, 'gender': '男', 'text': '安全第一条'},
3: {'name': '王五', 'age': 38, 'gender': '女', 'text': '行车不规范'},
}
# 转换器<int:nid>,相当于有名分组的作用
@app.route('/detail/<int:nid>', methods=['GET'])
def detail(nid):
# django获取session: request.session.get(key)
# flask从session中拿出user
user = session.get('user_info')
if not user:
return redirect('/login')
info = USERS.get(nid)
return render_template('detail.html', info=info)
@app.route('/index', methods=['GET'])
def index():
user = session.get('user_info')
if not user:
url = url_for('l1') # 反向解析
return redirect(url)
return render_template('index.html', user_dict=USERS)
@app.route('/login', methods=['GET', 'POST'], endpoint='l1') # endpoint别名,用作反向解析,如果不写,就用视图函数名作为别名
def login():
# django视图函数传入的是当次请求request
# flask的request是导入进来的,是全局request,如何区分是哪个url的请求?
if request.method == 'GET':
return render_template('login.html')
else:
# post请求提交过来的数据放在form中
# get请求提交过来的数据放在query_string中
user = request.form.get('user')
pwd = request.form.get('pwd')
if user == 'zl' and pwd == '123':
# django设置session: request.session[key] = value
# flask的session是导入进来的,是全局session,如何区分用户?
session['user_info'] = user
return redirect('/index')
return render_template('/login.html', error='用户名或密码错误')
if __name__ == '__main__':
app.run()
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户登录</h1>
<form action="" method="post">
<input type="text" name="user">
<input type="text" name="pwd">
<input type="submit" value="登录">{{error}}
</form>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户列表</h1>
<table>
<!--jinja2模板支持python语法,可以加括号调用方法-->
<!--jinja2模板的字典支持多种方式取值,django模板语法只支持v.name-->
{% for k, v in user_dict.items() %}
<tr>
<td>{{k}}</td>
<td>{{v.name}}</td>
<td>{{v['name']}}</td>
<td>{{v.get('name')}}</td>
<td><a href="/detail/{{k}}">查看详情</a></td>
</tr>
{% endfor %}
</table>
</body>
</html>
detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>详细信息 {{info.name}}</h1>
<div>
{{info.text}}
</div>
</body>
</html>