python与flask不得不说的小秘密
常识引入
-
什么是装饰器?
在不改变源码的前提下,对函数之前前后进行功能定制. 开放封闭原则:不改变函数内部代码,在函数外部进行修改.
-
基本写法
import functools def wrapper(func): @functools.wraps(func) def inner(*args, **kwargs): return func(*args, **kwargs) return inner @wrapper def index(xx): pass @wrapper def order(xx): pass print(index.__name__) # "inner" print(order.__name__) # "inner"
-
函数应用多个装饰器
import functools def wrapper1(func): @functools.wraps(func) def inner(*args, **kwargs): print('w1') return func(*args, **kwargs) return inner def wrapper2(func): @functools.wraps(func) def inner(*args, **kwargs): print('w2') return func(*args, **kwargs) return inner @wrapper1 @wrapper2 def index(): print('index') index()
flask和django不得不公布的绯闻
1.flask和django的区别?
flask,是一个轻量级的框架,内置了:路由/视图/模板(jinja2)/cookie/session/中间件. 可扩展强,第三方组件非常多,例如:wtforms/flask-session/flask-sqlalchemy.
django,是一个重武器,django内置了很多功能方便我们使用,例如:admin/orm/模板/form/modelform/session/cookie/中间件/路由/缓存/信号/数据库的读写分离/分页...
flask,短小精悍可扩展强.
django,大而全重武器.
-
django好还是flask好?
小程序,flask比较好. 中大型,django比较好.
2.快速入门
pip3 install flask
2.1 werkzurg
werkzurg是一个wsgi,本质上提供了socket服务端,用于接收用户请求.
django和flask一样,它们内部都没有实现socket服务端,需要依赖wsgi.
- django, wsgiref
- flask, werkzurg
2.1.1 wsgiref实现一个网站
from wsgiref.simple_server import make_server
class WSGIHandler(object):
def __call__(self,environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]
if __name__ == '__main__':
obj = WSGIHandler()
httpd = make_server('127.0.0.1', 8000, obj)
httpd.serve_forever()
2.1.2 werkzeug实现一个网站
from werkzeug.wrappers import Response
from werkzeug.serving import run_simple
class Flask(object):
def __call__(self,environ, start_response):
return Response('Hello World!')(environ, start_response)
if __name__ == '__main__':
app = Flask()
run_simple('127.0.0.1', 5000, app)
2.2 flask程序
from flask import Flask
# 实例化了一个Flask对象
app = Flask(__name__)
# 添加路由关系
@app.route('/index')
def index():
return '你好'
if __name__ == '__main__':
# 启动服务端
app.run()
3.flask用户登陆实例
关于返回值
```python
from flask import Flask,render_template,request,redirect
app = Flask(__name__)
@app.route('/login',methods=['GET','POST'])
def login():
return "xxx"
return render_template('模板文件',参数)
return redirect(...)
return jsonify({"k1":123})
if __name__ == '__main__':
app.run()
```
关于模板
```
默认放在根目录的tempaltes文件夹下
```
关于用户请求
```
request.method
request.form # POST请求传来的数据
request.args # GET url中的参数信息
```
session
```
加密的形式放在用户浏览器的cookie中.
# 登录操作
from flask import request, session
app.secret_key = 'sasashasalks'
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
if request.form['user'] == 'admin':
session['user'] = request.form['user']
return 'Hello World!'
else:
return 'No such user!'
if 'user' in session:
return 'Hello %s!' % session['user']
else:
title = request.args.get('title', 'Default')
return render_template('login.html', title=title)
```
在flask视图中添加装饰器
- 位置route的下面
- 记得加functools.wraps(...) , 保留函数的元信息.
特殊装饰器:before和after request装饰器
```
# 主要的是,执行顺序:before_request在视图函数执行前顺序执行,after_request在函数执行后,逆序执行(flask内部会先对after_request列表进行逆序再执行)
from flask import Flask,render_template,request,redirect,jsonify,url_for,session
import functools
app = Flask(__name__)
app.secret_key = "29ualknd872iuknsdgf"
@app.before_request
def f1():
print('f1')
@app.before_request
def f11():
print('f11')
@app.after_request
def f2(response):
print('f2')
return response
@app.after_request
def f22(response):
print('f22')
return response
@app.route('/login')
def login():
print('login')
return 'Login'
@app.route('/index')
def index():
print('index')
return 'index'
if __name__ == '__main__':
app.run()
# 显示顺序:
f1 f11 f22 f2 f1 f11 f22 f2
```
4. 路由中的重要参数
# 主要的
endpoint="" 默认是函数名, 可以在app.route()的关键字参数中定义,默认是对应的函数名,当登陆验证使用装饰器时,应注意装饰器的inner函数名会影响路由的解析,所以再装饰其中要使用funcktools.wraps(...)来保留原函数信息
url_for("") 反向地址, 通过视图函数名, 或endpoint解析对应的URL
methods=[] 该视图函数能处理的请求方式, 默认是GET, 当重新定义了methods, 那么默认的GET也会被覆盖
# 一般的
defaults={} 给视图函数传递参数, 可以作为默认参数, 传了就必须的接
strict_slashes=Bool 严格的使用"/", URL中没有"/", 访问时也不能有, URL中有"/", 你访问时没有, 会通过301进行永久重定向
redirect_to="" 永久重定向
# 动态路由参数
'/shopping/<int:year>/<string:month>' 路由中使用参数, 并可以转换参数的数据类型, 切记数字可以转字符串, 字符串不能转数字