WEB架構之Flask
Django:1個重武器,包含了web開發中常用的功能、元件的架構;(ORM、Session、Form、Admin、分頁、中間件、信号、緩存、ContenType....);
Tornado:2大特性就是異步非阻塞、原生支援WebSocket協定;
Flask:功能和性能雖然不及Django和Tornado,但是Flask的第三方開源元件比豐富;http://flask.pocoo.org/extensions/
Bottle:比較簡單;
總結:
都不是我寫的!!!不論優劣,不同的工具而已;
小型web應用設計的功能點不多使用Flask;
大型web應用設計的功能點比較多使用的元件也會比較多,使用Django(自帶功能多不用去找插件);
如果追求性能可以考慮Tornado;
Flask的socket是基于Werkzeug 實作的,模闆語言依賴jinja2模闆,在使用Flask之前需要安裝一下;
pip3 install flask #安裝flask
from werkzeug.wrappers import Request, Response # Flask的socket使用werkzeug實作,是以要導入 werkzeug
@Request.application
def hellow(request):
return Response('Hello World')
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost',400,hellow)
werkzeug
Flask簡單使用
from flask import Flask
app=Flask(__name__) #建立1個Flask執行個體
@app.route('/') #路由系統生成 視圖對應url,1. decorator=app.route() 2. decorator(first_flask)
def first_flask(): #視圖函數
return 'Hello World' #response
if __name__ == '__main__':
app.run() #啟動socket
View Code
一、配置檔案
app=Flask(__name__,template_folder='templates',static_url_path='/static/',static_path='/zhanggen')
模闆路徑: template_folder='templates'
靜态檔案路徑:static_url_path='/static/'
靜态檔案引入别名:static_path='/zhanggen'
設定為調試環境:app.debug=True (代碼修改自動更新)
設定json編碼格式 如果為False 就不使用ascii編碼:app.config['JSON_AS_ASCII']=False
設定響應頭資訊Content-Type app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" (注意 ;charset=utf-8)
二、路由系統
1.動态路由(url傳參)
@app.route('/user/<name>')
from flask import Flask
app=Flask(__name__)
@app.route('/<name>') #設定url傳參數 http://127.0.0.1:5000/zhanggen
def first_flask(name): #視圖必須有對應接收參數
print(name)
return 'Hello World' #response
if __name__ == '__main__':
app.run()
接收字元串類型參數
@app.route('/post/<int:age>')
#接收整型數字參數
app=Flask(__name__)
@app.route('/<int:age>/') #設定url傳參數 http://127.0.0.1:5000/18/
def first_flask(age): #視圖必須有對應接收參數
print(age)
return 'Hello World' #response
if __name__ == '__main__':
app.run()
接收整型數字參數
@app.route('/post/<float:salary>')
#接收浮點型型數字參數
app=Flask(__name__)
@app.route('/<float:salary>/') #設定url傳參數http://127.0.0.1:5000/2345555.8889/
def first_flask(salary): #視圖必須有對應接收參數
print(salary)
return 'Hello World' #response
if __name__ == '__main__':
app.run()
接收浮點型數字參數
@app.route('/post/<path:path>')
# 接收URL連結類型參數
app=Flask(__name__)
@app.route('/<path:url>/') #設定url傳參數:http://127.0.0.1:5000/http://www.baiu.com/
def first_flask(url): #視圖必須有對應接收參數
print(url)
return 'Hello World' #response
if __name__ == '__main__':
app.run()
接收URL連結類型參數
2、指定允許的請求方法
@app.route('/login', methods=['GET', 'POST'])
# 指定允許的請求方法
app=Flask(__name__)
@app.route('/<path:url>/',methods=['get']) #隻允許get請求
def first_flask(url):
print(url)
return 'Hello World' #response
if __name__ == '__main__':
app.run()
指定允許的請求方法
3、通過别名反向生成url
#反向生成url
from flask import Flask,url_for
app=Flask(__name__)
@app.route('/<path:url>',endpoint='name1')
def first_flask(url):
print(url_for('name1',url=url)) #如果設定了url參數,url_for(别名,加參數)
return 'Hello World'
if __name__ == '__main__':
app.run()
url_for()反向生成url
4、通過app.add_url_rule()調用路由
#方式2通過app.add_url_rule()方法的方式調用路由
app=Flask(__name__)
def first_flask():
return 'Hello World'
app.add_url_rule(rule='/index/',endpoint='name1',view_func=first_flask,methods=['GET'])
#app.add_url_rule(rule=通路的url,endpoint=路由别名,view_func=視圖名稱,methods=[允許通路的方法])
if __name__ == '__main__':
app.run()
app.add_url_rule()方法調用路由
5、擴充路由功能:正則比對url
如果需要一些複雜的比對規則可以自定義正則比對url
from flask import Flask, views, url_for
from werkzeug.routing import BaseConverter
app = Flask(import_name=__name__)
class RegexConverter(BaseConverter):
"""
自定義URL比對正規表達式
"""
def __init__(self, map, regex):
super(RegexConverter, self).__init__(map)
self.regex = regex
def to_python(self, value):
"""
路由比對時,比對成功後傳遞給視圖函數中參數的值
:param value:
:return:
"""
return int(value)
def to_url(self, value):
"""
使用url_for反向生成URL時,傳遞的參數經過該方法處理,傳回的值用于生成URL中的參數
:param value:
:return:
"""
val = super(RegexConverter, self).to_url(value)
return val
# 添加到flask中
app.url_map.converters['regex'] = RegexConverter
@app.route('/index/<regex("\d+"):nid>')
def index(nid):
print(url_for('index', nid='888'))
return 'Index'
if __name__ == '__main__':
app.run()
自定義正規表達式比對路由
四、視圖
1、給Flask視圖函數加裝飾器
注意如果要給視圖函數加裝飾器增加新功能,一點要加在路由裝飾器下面,才會被路由裝飾器裝飾,才能生生成url關系;
#給Flask視圖加裝飾器
#1、定義1個裝飾器
def auth(func):
print('我在上面')
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner
app=Flask(__name__)
@app.route('/',methods=['GET'])
@auth #注意如果要給視圖函數加裝飾器,一點要加在路由裝飾器下面,才會被路由裝飾器裝飾
def first_flask():
print('ffff')
return 'Hello World'
if __name__ == '__main__':
app.run()
View Code
2、request和response
a.請求相關資訊
request.method: 擷取請求方法
request.json
request.json.get("json_key"):擷取json資料 **較常用
request.argsget('name') :擷取get請求參數
request.form.get('name') :擷取POST請求參數
request.form.getlist('name_list'):擷取POST請求參數清單(多個)
request.values.get('age') :擷取GET和POST請求攜帶的所有參數(GET/POST通用)
request.cookies.get('name'):擷取cookies資訊
request.headers.get('Host'):擷取請求頭相關資訊
request.path:擷取使用者通路的url位址,例如(/,/login/,/ index/);
request.full_path:擷取使用者通路的完整url位址+參數 例如(/login/?age=18)
request.script_root: 抱歉,暫未了解其含義;
request.url:擷取通路url位址,例如http://127.0.0.1:5000/?age=18;
request.base_url:擷取通路url位址,例如 http://127.0.0.1:5000/;
request.url_root
request.host_url
request.host:擷取主機位址
request.files:擷取使用者上傳的檔案
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename)) 直接儲存
b、響應相關資訊
return "字元串" :響應字元串
return render_template('html模闆路徑',**{}):響應模闆
return redirect('/index.html'):跳轉頁面
響應json資料
方式1: return jsonify(user_list)
app.config['JSON_AS_ASCII']=False #指定json編碼格式 如果為False 就不使用ascii編碼,
app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" #指定浏覽器渲染的檔案類型,和解碼格式;
配置
方式2:
return Response(data,mimetype="application/json;charset=utf-8",)
如果需要設定響應頭就需要借助make_response()方法
from flask import Flask,request,make_response
response = make_response(render_template('index.html'))
response是flask.wrappers.Response類型
response.delete_cookie('key')
response.set_cookie('key', 'value')
response.headers['X-Something'] = 'A value'
return respons
3 、Flask之CBV視圖
#CBV視圖
from flask import Flask,url_for,views
#-----------------------------------------------------
app=Flask(__name__) #裝飾器
def auth(func):
print('我在上面')
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner
#--------------------------------------------------------
class IndexView(views.MethodView): #CBV視圖
methods=['GET'] #允許的http請求方法(改CBV隻允許GET方法)
decorators = [auth,] #每次請求過來都加auth裝飾器
def get(self):
return 'Index.GET'
def post(self):
return 'Index.POST'
app.add_url_rule('/index/',view_func=IndexView.as_view(name='name1')) #(name='name1'反向生成url别名
if __name__ == '__main__':
app.run()
CBV視圖
五、模闆語言
Flask使用的是Jinja2模闆,是以其文法和Django無差别(Django的模闆語言參考Jinja2)
1.引用靜态檔案
方式1:别名引入
<link rel="stylesheet" href="/zhanggen/commons.css">
方式2:url_for()方法引入
<link rel="stylesheet" href="{{ url_for('static',filename='commons.css') }}">
2.模闆語言引用上下文對象
變量
<h1>{{user_list}}</h1> <!--變量 -->
View Code
循環、索引取值
<ul>
{% for user in user_list %} <!--循環 -->
<li>{{user}}</li>
{% endfor %}
{{user_list.0}} <!-- 索引取值-->
</ul>
View Code
Flask的Jinjia2可以通過Context 把視圖中的函數傳遞把模闆語言中執行,這就是Django中的simple_tag和simple_fifter;
simple_tag(隻能傳2個參數,支援for、if)
@app.template_global() #simple_tag
def foo(arg):
return '<input type="text">'
視圖
<h1>{{foo(1)|safe}}</h1> <!--Flask的模闆語言支援simple_tag-->
模闆語言
simple_fifter(對參數個數無限制,不支援for、if)
@app.template_filter() #simple_fifter
def foo1(arg1,arg2,arg3):
return arg1+arg2+arg3
視圖
<h1> {{ 'alex'|foo1('s ','b',) }} </h1> <!-- simple_fifter -->
模闆語言
六、session功能
1. Flask自帶的session功能
from flask import session
import json
app=Flask(__name__,template_folder='templates',static_path='/static/',static_url_path='/static/')
app.debug=True
app.secret_key='sjehfjeefrjewth43u' #設定session加密
app.config['JSON_AS_ASCII']=False #指定json編碼格式 如果為False 就不使用ascii編碼,
app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" #指定浏覽器渲染的檔案類型,和解碼格式;
@app.route('/login/',methods=['GET','POST'])
def login():
msg = ''
if request.method=='POST':
name=request.values.get('user')
pwd=request.values.get('pwd')
if name =='zhanggen' and pwd=='123.com':
session['user']=name #設定session的key value
return redirect('/index/')
else:
msg='使用者名或者密碼錯誤'
return render_template('login.html',msg=msg)
@app.route('/index/',methods=['GET','POST'])
def index():
user_list = ['張根', 'egon', 'eric']
user=session.get('user') #擷取session
if user:
user=['alex','egon','eric']
return jsonify(user_list)
else:
return redirect('/login/')
if __name__ == '__main__':
app.run()
Flask自帶session功能
2.第三方session元件(Session)
安裝 pip install flask-session
from flask import session, Flask,request,make_response,render_template,redirect,jsonify,Response
from flask.ext.session import Session #引入第三方session
import json
app=Flask(__name__,template_folder='templates',static_path='/static/',static_url_path='/static/')
app.debug=True
app.secret_key='sjehfjeefrjewth43u' #設定session加密
app.config['JSON_AS_ASCII']=False #指定json編碼格式 如果為False 就不使用ascii編碼,
app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" #指定浏覽器渲染的檔案類型,和解碼格式;
app.config['SESSION_TYPE']='redis'
from redis import Redis #引入連接配接 redis子產品
app.config['SESSION_REDIS']=Redis(host='192.168.0.94',port=6379) #連接配接redis
Session(app)
@app.route('/login/',methods=['GET','POST'])
def login():
msg = ''
if request.method=='POST':
name=request.values.get('user')
pwd=request.values.get('pwd')
if name =='zhanggen' and pwd=='123.com':
session['user']=name #設定session的key value
return redirect('/index/')
else:
msg='使用者名或者密碼錯誤'
return render_template('login.html',msg=msg)
@app.route('/index/',methods=['GET','POST'])
def index():
user_list = ['張根', 'egon', 'eric']
user=session.get('user') #擷取session
if user:
user=['alex','egon','eric']
return jsonify(user_list)
else:
return redirect('/login/')
if __name__ == '__main__':
app.run()
把session存到redis
不僅可以把session存放到redis還可放到檔案、記憶體、memcache...
def _get_interface(self, app):
config = app.config.copy()
config.setdefault('SESSION_TYPE', 'null')
config.setdefault('SESSION_PERMANENT', True)
config.setdefault('SESSION_USE_SIGNER', False)
config.setdefault('SESSION_KEY_PREFIX', 'session:')
config.setdefault('SESSION_REDIS', None)
config.setdefault('SESSION_MEMCACHED', None)
config.setdefault('SESSION_FILE_DIR',
os.path.join(os.getcwd(), 'flask_session'))
config.setdefault('SESSION_FILE_THRESHOLD', 500)
config.setdefault('SESSION_FILE_MODE', 384)
config.setdefault('SESSION_MONGODB', None)
config.setdefault('SESSION_MONGODB_DB', 'flask_session')
config.setdefault('SESSION_MONGODB_COLLECT', 'sessions')
config.setdefault('SESSION_SQLALCHEMY', None)
config.setdefault('SESSION_SQLALCHEMY_TABLE', 'sessions')
if config['SESSION_TYPE'] == 'redis':
session_interface = RedisSessionInterface(
config['SESSION_REDIS'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'memcached':
session_interface = MemcachedSessionInterface(
config['SESSION_MEMCACHED'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'filesystem':
session_interface = FileSystemSessionInterface(
config['SESSION_FILE_DIR'], config['SESSION_FILE_THRESHOLD'],
config['SESSION_FILE_MODE'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'mongodb':
session_interface = MongoDBSessionInterface(
config['SESSION_MONGODB'], config['SESSION_MONGODB_DB'],
config['SESSION_MONGODB_COLLECT'],
config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'sqlalchemy':
session_interface = SqlAlchemySessionInterface(
app, config['SESSION_SQLALCHEMY'],
config['SESSION_SQLALCHEMY_TABLE'],
config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
config['SESSION_PERMANENT'])
else:
session_interface = NullSessionInterface()
return session_interface
View Code
3.自定義session元件
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import uuid
import json
from flask.sessions import SessionInterface
from flask.sessions import SessionMixin
from itsdangerous import Signer, BadSignature, want_bytes
class MySession(dict, SessionMixin):
def __init__(self, initial=None, sid=None):
self.sid = sid
self.initial = initial
super(MySession, self).__init__(initial or ())
def __setitem__(self, key, value):
super(MySession, self).__setitem__(key, value)
def __getitem__(self, item):
return super(MySession, self).__getitem__(item)
def __delitem__(self, key):
super(MySession, self).__delitem__(key)
class MySessionInterface(SessionInterface):
session_class = MySession
container = {}
def __init__(self):
import redis
self.redis = redis.Redis()
def _generate_sid(self):
return str(uuid.uuid4())
def _get_signer(self, app):
if not app.secret_key:
return None
return Signer(app.secret_key, salt='flask-session',
key_derivation='hmac')
def open_session(self, app, request):
"""
程式剛啟動時執行,需要傳回一個session對象
"""
sid = request.cookies.get(app.session_cookie_name)
if not sid:
sid = self._generate_sid()
return self.session_class(sid=sid)
signer = self._get_signer(app)
try:
sid_as_bytes = signer.unsign(sid)
sid = sid_as_bytes.decode()
except BadSignature:
sid = self._generate_sid()
return self.session_class(sid=sid)
# session儲存在redis中
# val = self.redis.get(sid)
# session儲存在記憶體中
val = self.container.get(sid)
if val is not None:
try:
data = json.loads(val)
return self.session_class(data, sid=sid)
except:
return self.session_class(sid=sid)
return self.session_class(sid=sid)
def save_session(self, app, session, response):
"""
程式結束前執行,可以儲存session中所有的值
如:
儲存到resit
寫入到使用者cookie
"""
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
httponly = self.get_cookie_httponly(app)
secure = self.get_cookie_secure(app)
expires = self.get_expiration_time(app, session)
val = json.dumps(dict(session))
# session儲存在redis中
# self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime)
# session儲存在記憶體中
self.container.setdefault(session.sid, val)
session_id = self._get_signer(app).sign(want_bytes(session.sid))
response.set_cookie(app.session_cookie_name, session_id,
expires=expires, httponly=httponly,
domain=domain, path=path, secure=secure)
元件
from flask import Flask
from flask import session
from my_session import MySessionInterface
app = Flask(__name__)
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
app.session_interface = MySessionInterface()
@app.route('/login/', methods=['GET', "POST"])
def login():
print(session)
session['user1'] = 'alex'
session['user2'] = 'alex'
del session['user2']
return "内容"
if __name__ == '__main__':
app.run()
應用
七、藍圖
使用Flask自帶Blueprintmuk子產品,幫助我們做代碼目錄結構的歸類
import luffy #導入luffy包就會執行luffy包中__init__.py檔案
luffy.app.run()
app.py
from flask import Flask
app=Flask(__name__,template_folder='templates',static_path='/static/',static_url_path='/static/')
app.debug=True
from .views import login
from .views import index
#把檔案中藍圖對象注冊到app裡
app.register_blueprint(login.login,url_prefix='/login') #通路login藍圖必須以url_prefix開頭
app.register_blueprint(index.index,url_prefix='/index')
if __name__ == '__main__':
app.run()
luffy包的__init__.py
from flask import Blueprint #導入藍圖
login=Blueprint('login',__name__) #在本子產品執行個體化1個藍圖
@login.route('/login/',methods=['GET','POST'])
def login1():
return '登入頁面'
login
from flask import Blueprint
index=Blueprint('index',__name__)
@index.route('/index/',methods=['GET','POST'])
def index1():
return '首頁'
index
八、message (閃現)
message是一個基于Session實作的用于儲存資料的集合,其特點是:一次性。
特點:和labada匿名函數一樣不長期占用記憶體
from flask import Flask,request,flash,get_flashed_messages
app = Flask(__name__)
app.secret_key = 'some_secret'
@app.route('/set/')
def index2():
flash('Disposable') #在message中設定1個個值
return 'ok'
#---------------------------------------------------------------------------------
@app.route('/')
def index1():
messages = get_flashed_messages() #擷取message中設定的值,隻能擷取1次。(1次性)
print(messages)
return "Index1"
if __name__ == "__main__":
app.run()
flask_message
九、中間件
flask也有中間件功能和Django類似,不同的是使用的是使用3個裝飾器來實作的;
[email protected]_first_request :請求第1次到來執行1次,之後都不執行;
[email protected]_request:請求到達視圖之前執行;(改函數不能有傳回值,否則直接在目前傳回)
[email protected]_request:請求 經過視圖之後執行;(最下面的先執行)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, Request, render_template
app = Flask(__name__, template_folder='templates')
app.debug = True
@app.before_first_request #第1個請求到來執行
def before_first_request1():
print('before_first_request1')
@app.before_request #中間件2
def before_request1():
Request.nnn = 123
print('before_request1') #不能有傳回值,一旦有傳回值在目前傳回
@app.before_request
def before_request2():
print('before_request2')
@app.errorhandler(404)
def page_not_found(error):
return 'This page does not exist', 404
@app.route('/')
def hello_world():
return "Hello World"
@app.after_request #中間件 執行視圖之後
def after_request1(response):
print('after_request1', response)
return response
@app.after_request #中間件 執行視圖之後 先執行 after_request2
def after_request2(response):
print('after_request2', response)
return response
if __name__ == '__main__':
app.run()
View Code
十、Flask插件
WTForms
SQLAchemy
等... 詳細見:http://flask.pocoo.org/extensions/
文檔:http://docs.jinkan.org/docs/flask/quickstart.html
轉載于:https://www.cnblogs.com/taosiyu/p/11371419.html