一. Python 现阶段三大主流Web框架 Django Tornado Flask 对比
1.Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不管你用得到用不到,反正它全都有,属于全能型框架
2.Tornado 主要特点是原生异步非阻塞,在IO密集型应用和多任务处理上占据绝对性的优势,属于专注型框架
3.Flask 主要特点小而轻,原生组件几乎为0, 三方提供的组件请参考Django 非常全面,属于短小精悍型框架
Django 通常用于大型Web应用由于内置组件足够强大所以使用Django开发可以一气呵成
Tornado 通常用于API后端应用,游戏服务后台,其内部实现的异步非阻塞真是稳得一批
Flask 通常应用于小型应用和快速构建应用,其强大的三方库,足以支撑一个大型的Web应用
Django 优点是大而全,缺点也就暴露出来了,这么多的资源一次性全部加载,肯定会造成一部分的资源浪费
Tornado 优点是异步,缺点是干净,连个Session都不支持
Flask 优点是精悍简单
总结:
Flask:
优点:小而精,短小精悍,第三方组件特别多
缺点:组件更新速度取决于开源者,你不会
Tornado:
优点:原生的WebSocket,异步任务,IO非阻塞
缺点:组件没有,Session都没有
Django:
优点:大而全,组件非常全面
缺点:太大,加载太大,浪费资源
二、Flask 的安装与简单使用
pip install Flask
最简单的Flask项目,Flask三行:
from flask import Flask apl = Flask(__name__) apl.run()
三、三种返回页面的方式
from flask import Flask, render_template, redirect # 一个flask对象 app = Flask(__name__)
STUDENT_LIST = [ {'name': 'Old', 'age': 38, 'gender': '中'},
{'name': 'Boy', 'age': 73, 'gender': '男'},
{'name': 'EDU', 'age': 84, 'gender': '女'} ]# render 注意, templates文件要和当前py文件同级,不然会找不到,报一个Jinja2的异常哦 @app.route('/index') def index(): html_msg = '<h1>my html</h1>' markup_tag = Markup(html_msg) # 相当于在html页面加上 safe ,这里写了,前端页面就不用写了 return render_template('index.html', stu=STUDENT_LIST, markup_tag=markup_tag, tag="") # HTTPResponse @app.route('/') def one_test(): return 'hello girl' # redirect @app.route('/hello') def hello(): return redirect('/index')
if __name__ == '__main__':
# debug模式运行
app.run(debug=True)
四、模版语言
1.模版函数
2、数据安全
3、 for if 等的用法和django里的一样
4、模版继承的用法也和django一样,就不写了
举个栗子:
在 app.py 中
######### 在Jinja2中执行Python函数(模板中执行函数) ############ @app.template_global() # 定义全局模板函数 def a_b_sum(a, b): return a + b @app.template_filter() # 定义全局模板函数 def a_b_c_sum(a, b, c): return a + b + c def index(): html_msg = '<h1>my html</h1>' markup_tag = Markup(html_msg) # 相当于在html页面加上 safe ,这里写了,前端页面就不用写了 return render_template('index.html', stu=STUDENT_LIST, markup_tag=markup_tag, tag="")
在index.html页面里
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <!-- 在Jinja2中执行Python函数(模板中执行函数) --> {{ a_b_sum(99,1) }} <br> {{ 1 | a_b_c_sum(197,2) }} <!-- 插入 markup 处理后的html标签 --> {{ markup_tag }} <table> <thead> <tr> {% for foo in stu[0] %} <td>{{ foo }}</td> {% endfor %} </tr> </thead> <tbody> {% for st in stu %} <tr> {% for t in st %} <td>{{ st[t] }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </body> </html>
五、一个简单的登录认证
2、session的应用
- Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪
- secret_key 实际上是用来加密字符串的,如果在实例化的app中没有 secret_key 那么开启session一定会抛异常的
- cookies 中 session 存储的是通过 secret_key 加密后的 key , 通过这个 key 从flask程序的内存中找到用户对应的session信息
3、装饰器的使用及遇到的问题
4、类似Django中间件,.@app.before_request 和 @app.after_request errorheadler
先看代码吧~
在app.py中:
from flask import Markup # 导入 flask 中的 Markup 模块 from flask import Flask, render_template, redirect from flask import request from flask import session # 一个flask对象 app = Flask(__name__) # cookies 中 session 存储的是通过 secret_key 加密后的 key , 通过这个 key 从flask程序的内存中找到用户对应的session信息 app.secret_key = "LYJ" import functools # 一个认证装饰器 def my_auth(func): @functools.wraps(func) def war(*args, **kwargs): if session.get('user'): return func() else: return redirect('/login') return war @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': print(request.form) # ImmutableMultiDict([('username', 'qwe'), ('pwd', '123')]) username = request.form['username'] # 以字典方式取值 pwd = request.form.get('pwd') print(username, pwd) # session的应用 session['user'] = username return redirect('/index') if request.method == 'GET': return render_template('login.html') # 认证,自定义装饰器的使用 @app.route('/index2', endpoint='index2') @my_auth def index2(): return redirect('/index') #用的是示例模版的那个index @app.route('/index3', endpoint='index3') @my_auth def index3(): return redirect('/index') # AssertionError: View function mapping is overwriting an existing endpoint function: war # 因为在经过装饰器后 func 的 __name__都变成了装饰器的名字,所以 route 在处理时,会取到多个一样的方法名 # 有两种解决办法 1、 在装饰器中加上 装饰器修复 @functools.wraps(func) 2、 用endpoint给传入route的函数命名: @app.route('/index3',endpoint='index3') if __name__ == '__main__': # debug模式运行 app.run(debug=True)
如果直接加装饰器的话,会报错
AssertionError: View function mapping is overwriting an existing endpoint function: war
原因:在经过装饰器后 func 的 __name__都变成了装饰器的名字,所以 route 在处理时,会取到多个一样的方法名
有两种解决办法:
1、 在装饰器中加上 装饰器修复 @functools.wraps(func)
2、 用endpoint给传入route的函数命名: @app.route('/index3',endpoint='index3')
注意:
装饰器应该放在最靠近函数的地方,因为装饰器的执行顺序是从最靠近的那个开始的,不这样写的话会不行该函数,详见:多个装饰器的执行顺序
另一种处理登录认证的方式,类似于Django的中间件
1.@app.before_request 在请求(request)之前做出响应
from flask import Flask
from flask import request
from flask import redirect
from flask import session
app = Flask(__name__) # type:Flask
app.secret_key = "DragonFire"
@app.before_request
def is_login():
if request.path == "/login":
return None
if not session.get("user"):
return redirect("/login")
@app.route("/login")
def login():
return "Login"
@app.route("/index")
def index():
return "Index"
@app.route("/home")
def home():
return "Login"
app.run("0.0.0.0", 5000)
@app.before_request 也是一个装饰器,他所装饰的函数,都会在请求进入视图函数之前执行
request.path 是来读取当前的url地址如果是 /login 就允许直接通过 return None 你可以理解成通过放行
校验session中是否有user 如果没有的话,证明没有登录,所以毫不留情的 redirect("/login") 跳转登录页面
还有一个要提的 @app.before_first_request 它与 @app.before_request 极为相似或者说是一模一样,只不过它只会被执行一次
2. @app.after_request 在响应(response)之前做出响应
@app.after_request
def foot_log(environ):
if request.path != "/login":
print("有客人访问了",request.path)
return environ
3. errorheadler(404) 定义错误信息
def error_page(arg) 错误信息头
4、flash 导入
flash("message") get_flashed_messages() 导入
一存放,一提取,消失
很少应用,但是要了解有这么个东西