
一、 flask簡介
Flask是一個使用 Python編寫的輕量級 Web 應(yīng)用框架。其 WSGI工具箱采用 Werkzeug ,模板引擎則使用 Jinja2 。
WSGI
Web服務(wù)器網(wǎng)關(guān)接口(WSGI)已被用作Python Web應(yīng)用程序開發(fā)的標準。WSGI是Web服務(wù)器和Web應(yīng)用程序之間通用接口的規(guī)范。
Werkzeug
它是一個WSGI工具包,它實現(xiàn)了請求,響應(yīng)對象和其他實用函數(shù)。這使得能夠在其上構(gòu)建Web框架。Flask框架使用Werkzeug作為其基礎(chǔ)之一。
Jinga2
Jinja2是Python的一個流行的模板引擎。Web模板系統(tǒng)將模板與特定數(shù)據(jù)源組合以呈現(xiàn)動態(tài)網(wǎng)頁。Flask通常被稱為微框架。它旨在保持應(yīng)用程序的核心簡單而可擴展。Flask沒有用于數(shù)據(jù)庫處理的內(nèi)置抽象層,也沒有形成驗證支持。相反,F(xiàn)lask支持擴展以向應(yīng)用程序添加此類功能。
二、flask路由
路由定義
處理url和函數(shù)之間綁定關(guān)系的程序,是指Flask 根據(jù)客戶端請求 的 URL,查找對應(yīng)的視圖函數(shù) (view function),由視圖函數(shù)進行處理后,返回 response 到客戶端。
路由作用
路由控制訪問的路徑,路徑能訪問到什么是由后端來控制的
1 route裝飾器 :可以使用Flask應(yīng)用實例的route裝飾器將一個URL規(guī)則綁定到 一個視圖函數(shù)上。
# -*- coding:utf8 -*-
from flask import Flask
app = Flask(__name__)
@app.route('/index')
def index():
return '<h1>index page</h1>'
if __name__ == '__main__':
# url_map : 儲存 url 和 endpoint 的映射(url_map 的數(shù)據(jù)類型是 werkzeug.routing.Map)
print(app.url_map)
app.run(port=5000,debug=True)
2 add_url_rule方法定義路由
add_url_rule() :另一種等價的寫法是使用Flask應(yīng)用實例的add_url_route()方法。
route裝飾器內(nèi)部也是通過調(diào)用add_url_route()方法實現(xiàn)的路由注冊。 但是顯然,使用裝飾器使代碼看起來更優(yōu)雅一些。
# -*- coding:utf8 -*-
from flask import Flask
app = Flask(__name__)
def about(user_id):
return 'about page %d' % user_id
app.add_url_rule(rule='/about/<int:user_id>',view_func=about)
if __name__ == '__main__':
app.run(port=5000, debug=True)
3 自定義路由(需要重新定義父類。注意python2與python3的差別?。。。?/h6>
# -*- coding:utf8 -*-
from flask import Flask
from werkzeug.routing import BaseConverter #導入轉(zhuǎn)換器包
app = Flask(__name__)
# flask自帶幾種轉(zhuǎn)換器
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
# 自定義路由表達式
class RegexConverter(BaseConverter):
def __init__(self, url_map, regex):
super(RegexConverter,self).__init__(map=url_map) # python2 重寫父類super需要傳入子類參數(shù)
# super().__init__(map=url_map) # python3 重寫父類super不需要傳入子類參數(shù)
# self.regex = r'1[3-9]{2}\d{8}'
self.regex = regex
# 自定義路由表達式:手機號匹配
class MobileConverter(BaseConverter):
def __init__(self, url_map):
super(MobileConverter,self).__init__(map=url_map) # python2 重寫父類super需要傳入子類參數(shù)
# super().__init__(map=url_map) # python3 重寫父類super不需要傳入子類參數(shù)
self.regex = r'1[3-9]{2}\d{8}'
# 將自定義轉(zhuǎn)換器類添加到轉(zhuǎn)換器字典中
app.url_map.converters['re'] = RegexConverter
app.url_map.converters['mobile'] = MobileConverter
# @app.route('/goods/<float:hello>')
# @app.route('/goods/<int:hello>')
@app.route('/goods/<string:hello>') # hello 參數(shù)為變量
def index(hello):
return 'hello world %s' % hello
@app.route('/index/<re(r"1[3-9]{2}\d{8}"):test1>')
def sed(test1):
return "<h1>this for test %s</h1>" % test1
@app.route('/send/<mobile:mobile>')
def send(mobile):
print ("phone number is %s " % mobile)
return "<h1>your phone number is %s </h1>" % mobile
if __name__ == '__main__':
print(app.url_map)
app.run(host='0.0.0.0',debug=True,port=2000)
4 多個裝飾器實現(xiàn)多個路由,/,/h1,/index都可以映射同一函數(shù)
# -*- coding:utf8 -*-
from flask import Flask
app = Flask(__name__)
# 多個裝飾器可以實現(xiàn)多個路由功能
@app.route('/index')
@app.route('/')
@app.route('/h1')
def index():
return '<h1>index page</h1>'
if __name__ == '__main__':
app.run(port=5000,debug=True)
5 路由請求方式設(shè)置,methods參數(shù)可以提供可選的請求方式
# -*- coding:utf8 -*-
from flask import Flask
app = Flask(__name__)
@app.route('/post',methods=['POST','GET','PUT','DELETE'])
def only():
return 'post only page'
if __name__ == '__main__':
print app.url_map
app.run(host='0.0.0.0',debug=True,port=2000)
6 flask URL構(gòu)建
# -*- coding:utf8 -*-
from flask import Flask
from werkzeug.routing import BaseConverter #導入轉(zhuǎn)換器包
app = Flask(__name__)
# flask自帶幾種轉(zhuǎn)換器
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
# 自定義路由表達式
class RegexConverter(BaseConverter):
def __init__(self, url_map, regex):
super(RegexConverter,self).__init__(map=url_map) # python2 重寫父類super需要傳入子類參數(shù)
# super().__init__(map=url_map) # python3 重寫父類super不需要傳入子類參數(shù)
# self.regex = r'1[3-9]{2}\d{8}'
self.regex = regex
# 自定義路由表達式:手機號匹配
class MobileConverter(BaseConverter):
def __init__(self, url_map):
super(MobileConverter,self).__init__(map=url_map) # python2 重寫父類super需要傳入子類參數(shù)
# super().__init__(map=url_map) # python3 重寫父類super不需要傳入子類參數(shù)
self.regex = r'1[3-9]{2}\d{8}'
# 將自定義轉(zhuǎn)換器類添加到轉(zhuǎn)換器字典中
app.url_map.converters['re'] = RegexConverter
app.url_map.converters['mobile'] = MobileConverter
# @app.route('/goods/<float:hello>')
# @app.route('/goods/<int:hello>')
@app.route('/goods/<string:hello>') # hello 參數(shù)為變量
def index(hello):
return 'hello world %s' % hello
@app.route('/index/<re(r"1[3-9]{2}\d{8}"):test1>')
def sed(test1):
return "<h1>this for test %s</h1>" % test1
@app.route('/send/<mobile:mobile>')
def send(mobile):
print ("phone number is %s " % mobile)
return "<h1>your phone number is %s </h1>" % mobile
if __name__ == '__main__':
print(app.url_map)
app.run(host='0.0.0.0',debug=True,port=2000)
# -*- coding:utf8 -*-
from flask import Flask
app = Flask(__name__)
# 多個裝飾器可以實現(xiàn)多個路由功能
@app.route('/index')
@app.route('/')
@app.route('/h1')
def index():
return '<h1>index page</h1>'
if __name__ == '__main__':
app.run(port=5000,debug=True)
# -*- coding:utf8 -*-
from flask import Flask
app = Flask(__name__)
@app.route('/post',methods=['POST','GET','PUT','DELETE'])
def only():
return 'post only page'
if __name__ == '__main__':
print app.url_map
app.run(host='0.0.0.0',debug=True,port=2000)
url_for()函數(shù)對于動態(tài)構(gòu)建特定函數(shù)的URL非常有用。該函數(shù)接受函數(shù)的名稱作為第一個參數(shù),以及一個或多個關(guān)鍵字參數(shù),每個參數(shù)對應(yīng)于URL的變量部分。
以下腳本演示了如何使用url_for()函數(shù):
# -*- coding:utf8 -*-
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/admin')
def hello_admin():
return 'Hello Admin'
@app.route('/guest/<guest>')
def hello_guest(guest):
return 'Hello %s as Guest' % guest
@app.route('/user/<name>')
def hello_user(name):
if name =='admin':
return redirect(url_for('hello_admin'))
else:
return redirect(url_for('hello_guest',guest = name))
if __name__ == '__main__':
app.run(debug = True)
三、flask靜態(tài)文件
1、可以在創(chuàng)建app的時候使用以下參數(shù)進行設(shè)置
app = Flask(__name__,template_folder='wangze',static_folder='static',static_url_path='/static')
參數(shù)作用
在視圖中的Flask類中的參數(shù)作用:
1. template_folder 是存放頁面的文件夾,默認是templates
2. static_folder 是靜態(tài)文件夾的名字
3. static_url_path 是靜態(tài)文件的路徑,跟前端頁面中的url路徑一致
2 flask模板文件配置
(1) 模板文件修改代碼演示,更改 template_folder 為 wangze
python代碼部分
from flask import Flask,render_template
app = Flask(__name__,template_folder='wangze',static_folder='static',static_url_path='/static')
@app.route('/index')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(port=4002,debug=True)
index.html部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1> hello world</h1>
</body>
</html>
(2)、發(fā)送請求: http://127.0.0.1:4002/index

3 flask靜態(tài)文件配置(適用python3,python2會報錯)
(1) python 代碼部分
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template("hello.html")
if __name__ == '__main__':
app.run(debug=True,port=4004)
(2) 與python代碼同級目錄templates/index.html部分
<!DOCTYPE html>
<html lang="en">
<head>
<script type = "text/javascript"
src = "{{ url_for('static', filename = 'hello.js') }}" ></script>
</head>
<body>
<img src="{{ url_for('static',filename='test2.jpg')}}" width="120" height="60"/> <br>
<input type = "button" onclick = "sayHello()" value = "Say Hello" />
</body>
</html>
(3) 與python代碼同級目錄static/js文件內(nèi)容
function sayHello() {
alert("Hello World")
}
(4) 目錄結(jié)構(gòu),與templates同級目錄

(5)demo:發(fā)送請求

四、flask模版方法
(1)demo.py
# encoding=utf-8
from flask import Flask, render_template
app = Flask(__name__)
user = {"username": "xiao xiao", "bio": "A girl who loves movies."}
movies = [
{'name': 'My Neighbor Totoro', 'year': '1988'},
{'name': 'Three Colours trilogy', 'year': '1993'},
{'name': 'Forrest Gump', 'year': '1994'},
{'name': 'Perfect Blue', 'year': '1997'},
{'name': 'The Matrix', 'year': '1999'},
{'name': 'Memento', 'year': '2000'},
{'name': 'The Bucket list', 'year': '2007'},
{'name': 'Black Swan', 'year': '2010'},
{'name': 'Gone Girl', 'year': '2014'},
{'name': 'CoCo', 'year': '2017'}
]
@app.route('/hi')
def hi():
return "hello flask!"
@app.route("/watchlist")
def watchlist():
return render_template("watchlist.html", user=user, movies=movies)
if __name__ == "__main__":
app.run(debug=True,port=4001)
(2) templates/index.html 模版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ user.username }}'s watchlist</title>
</head>
<body>
跳轉(zhuǎn)到 h1方法 <br>
<a href="{{ url_for('hi') }}">← Return</a>
<h2>{{ user.username}}</h2>
{% if user.bio %}
<i>{{ user.bio }}</i>
{% else %}
<i>This user has not provided a bio.</i>
{% endif %}
{# 以下是電影清單(這是注釋) #}
<h5>{{ user.username }}'s watchlist ({{ movies|length }}):</h5>
<ul>
{% for movie in movies %}
<li>{{ movie.name }} - {{ movie.year }}</li>
{% endfor %}
</ul>
<hr>
{% for k,v in user.items() %}
{{ k }} -- {{ v }} <br>
{% endfor %}
<hr>
{% if user.get('username') == "xiao xiao" %}
{{user}}
{% endif %}
</body>
</html>
五、flask配置參數(shù)設(shè)置
1 demo.py
# -*- coding:utf8 -*-
import emoji
import random
from flask import Flask,current_app
app = Flask(__name__,template_folder='templates')
# 配置參數(shù)的使用形式
# 1 將配置寫到配置文件中
app.config.from_pyfile('config.cfg')
# 2 使用對象配置參數(shù)
class Config(object):
DEBUG = True
ITCAST = 'python'
app.config.from_object(Config)
# 3 直接操作config字典對象
app.config['DEBUG'] = True
@app.route('/')
def index():
# 讀取配置參數(shù)
# 1 直接從全局對象app的config字典中讀取
# print app.config.get('ITCAST')
# 2 通過current_app獲取config中的參數(shù)
print current_app.config.get('ITCAST')
# a = 1/0
my_emoji = random.choice(emoji.EMOJI_UNICODE.keys())
b = emoji.EMOJI_UNICODE.get(my_emoji)
return '<h1>emoji is %s</h1>'%b
if __name__ == '__main__':
app.run(port=1998)
2 config.cfg文件內(nèi)容
DEBUG = True
在同級目錄下

六、flask藍圖
Why?
我們將所有的Flask請求方法都寫在同一個文件下的話,非常不便于我們代碼管理和后期功能代碼的添加。比如:我們在一個文件中寫入多個路由,這會使代碼維護變得困難。
1 創(chuàng)建一個主的路由配置文件manage.py,該文件主要的作用就是啟動整個的Flask框架(項目)
# -*- coding:utf8 -*-
from flask import Flask
from admin.admin import admin1 as admin_blueprint # 導入藍圖
from front.front import front1 as front_blueprint # 導入藍圖
app = Flask(__name__)
app.register_blueprint(admin_blueprint) # 注冊藍圖
app.register_blueprint(front_blueprint) # 注冊藍圖
if __name__ == '__main__':
app.run(debug=True, port=2008)
2 在同級目錄下創(chuàng)建 admin、front兩個目錄
mkdir admin && mkdir front
目錄結(jié)構(gòu)如圖(注意:admin.py及init.py文件在admin目錄下):

3 admin.py 文件內(nèi)容
# -*- coding:utf8 -*-
from flask import Blueprint, render_template
admin1 = Blueprint('admin', __name__, url_prefix='/admin')
@admin1.route('/index')
def index():
return 'index'
@admin1.route('/register')
def register():
return 'register'
@admin1.route('/login')
def login():
return '<h1>login</h1>'
4 front.py 文件內(nèi)容
from flask import Blueprint
front1 = Blueprint('front', __name__)
@front1.route('/add')
def add():
return 'add'
@front1.route('/delete')
def delete():
return 'delete'
七、flask表單擴展
1 表單擴展 test.py
# -*- coding:utf8 -*-
from flask import Flask,render_template
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import EqualTo,DataRequired
app = Flask(__name__)
app.secret_key = '!@#T^@#!*#@#@!#@!#'
# 定義表單模型類
class RegisterForm(FlaskForm):
# 自定義注冊表單模型類
# DataRequired 保證數(shù)據(jù)必須填寫,且不能為空
user_name = StringField(label=u'用戶',validators=[DataRequired(u'用戶名不能為空')])
password = PasswordField(label=u'密碼',validators=[DataRequired(u'密碼不能為空')])
password2 = PasswordField(label=u'確認密碼',validators=[DataRequired(u'密碼不能為空'),
EqualTo('password',u'兩次密碼不一致')])
submit = SubmitField(label=u'提交')
@app.route('/register',methods =['POST','GET'])
def register():
#
form = RegisterForm()
return render_template('register.html',form=form)
if __name__ == '__main__':
app.run(port=5001,debug=True)
2 templates/register.html 內(nèi)容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>register</title>
</head>
<body>
<form method="post" action="/register">
{{ form.user_name.label }}
<p>{{ form.user_name }}</p >
{% for msg in form.user_name.errors %}
<p>{{ msg }}</p >
{% endfor %}
{{ form.password.label }}
<p>{{ form.password }}</p >
{% for msg in form.password.errors %}
<p>{{ msg }}</p >
{% endfor %}
{{ form.password2.label }}
<p>{{ form.password2 }}</p >
{% for msg in form.password2.errors %}
<p>{{ msg }}</p >
{% endfor %}
{{ form.submit }}
</form>
</body>
</html>