前言:
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)
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
一、配置檔案
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()
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()
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()
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()
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()
五、模闆語言
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> <!--變量 -->
循環、索引取值

<ul>
{% for user in user_list %} <!--循環 -->
<li>{{user}}</li>
{% endfor %}
{{user_list.0}} <!-- 索引取值-->
</ul>
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 -->
3.wtform(flask表單驗證插件)
3.0.簡介
wtforms WTForms是一個支援多個web架構的form元件,主要對使用者請求資料 進行表單驗證。
3.1. 安裝
pip install wtforms #安裝wtfroms插件
3.2.簡單使用
wtforms和Django自帶的form驗證插件功能相同,使用起來大同小異;
使用者登入頁面驗證

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets
app=Flask(__name__,template_folder='templates') #知道模闆檔案
app.debug=True
#登入驗證執行個體
class LoginForm(Form):
#不同的字段 内部包含正規表達式 html5.EmailField | html5.DateTimeField...
name=simple.StringField(
label='使用者名',
validators=[ #驗證規則和錯誤提示資訊
validators.DataRequired(message='使用者名不能為空.'),
validators.Length(min=6, max=18, message='使用者名長度必須大于%(min)d且小于%(max)d')
],
widget=widgets.TextInput(), #前端頁面顯示的插件.TextArea
render_kw={'class': 'form-control'} #設定form标簽的class資訊
)
# 不同的字段 内部包含正規表達式 html5.EmailField | html5.DateTimeField...
pwd = simple.PasswordField(
label='密碼',
validators=[
validators.DataRequired(message='密碼不能為空.'),
validators.Length(min=8, message='使用者名長度必須大于%(min)d'),
#自定義驗證規則
validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
message='密碼至少8個字元,至少1個大寫字母,1個小寫字母,1個數字和1個特殊字元')
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
)
@app.route('/login/', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
form = LoginForm() #執行個體化 form驗證類
return render_template('login.html', form=form)
else:
form = LoginForm(formdata=request.form)
if form.validate(): #判斷是否驗證成功?
print('使用者送出資料通過格式驗證,送出的值為:', form.data)
else:
print(form.errors)
return render_template('login.html', form=form)
if __name__ == '__main__':
app.run()

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登入</h1>
<form method="post" novalidate>
<!--<input type="text" name="name">-->
<p>{{form.name.label}} {{form.name}} {{form.name.errors[0] }}</p>
<!--<input type="password" name="pwd">-->
<p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}</p>
<input type="submit" value="送出">
</form>
</body>
</html>
login.html
使用者注冊頁面驗證

#使用者注冊
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets
app = Flask(__name__, template_folder='templates')
app.debug = True
class RegisterForm(Form):
name = simple.StringField(
label='使用者名',
validators=[
validators.DataRequired()
],
widget=widgets.TextInput(),
render_kw={'class': 'form-control'},
default='張根' #設定input标簽中預設值
)
pwd = simple.PasswordField(
label='密碼',
validators=[
validators.DataRequired(message='密碼不能為空.')
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
)
pwd_confirm = simple.PasswordField( #第二次輸入密碼
label='重複密碼',
validators=[
validators.DataRequired(message='重複密碼不能為空.'),
validators.EqualTo('pwd', message="兩次密碼輸入不一緻") #驗證2次輸入的密碼是否一緻?
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
)
email = html5.EmailField(
label='郵箱',
validators=[
validators.DataRequired(message='郵箱不能為空.'),
validators.Email(message='郵箱格式錯誤')
],
widget=widgets.TextInput(input_type='email'), #生成email input标簽
render_kw={'class': 'form-control'}
)
gender = core.RadioField(
label='性别',
choices=( #choice radio選項
(1, '男'),
(2, '女'),
),
coerce=int #講使用者送出過來的 '4' 強制轉成 int 4
)
city = core.SelectField(
label='城市',
choices=(
('bj', '北京'),
('sh', '上海'),
)
)
hobby = core.SelectMultipleField( #select 下拉框多選框
label='愛好',
choices=(
(1, '籃球'),
(2, '足球'),
),
coerce=int
)
favor = core.SelectMultipleField(
label='喜好',
choices=(
(1, '籃球'),
(2, '足球'),
),
widget=widgets.ListWidget(prefix_label=False), #生成Checkbox 多選框
option_widget=widgets.CheckboxInput(),
coerce=int,
default=[1, 2]
)
def __init__(self, *args, **kwargs): #重寫form驗證類的__init__方法可以實時同步資料中資料
super(RegisterForm, self).__init__(*args, **kwargs)
self.favor.choices = ((1, '籃球'), (2, '足球'), (3, '羽毛球'))
def validate_pwd_confirm(self, field): #wtforms驗證 鈎子函數
"""
自定義pwd_confirm字段規則,例:與pwd字段是否一緻
:param field:
:return:
"""
# 最開始初始化時,self.data中已經有所有的值
if field.data != self.data['pwd']:
# raise validators.ValidationError("密碼不一緻") # 繼續後續驗證
raise validators.StopValidation("密碼不一緻") # 不再繼續後續驗證
@app.route('/register/', methods=['GET', 'POST'