官方文檔: http://flask.pocoo.org/docs/0.11/
中文文檔: http://docs.jinkan.org/docs/flask/
HTTP協議:
請求
- 請求行
- 請求頭
- 請求體
響應
響應行
HTTP / 1.1 200 OK
響應狀態:
- 200:響應成功
- 302:重定向
- 304:資源未更新
- 404:資源不存在
- 500:服務器內部錯誤
- 鍵值對:說明
Content-Type:文件類型 text/html image/jpeg application/json text/xml
- 響應體
1.定義正則:
1.導包
from werkzeug.routing import BaseConverter
2.創建正則類,重寫__init__
方法,並調用父類方法
class XXXX(BaseConverter):
def __init__(self, url_map, *args): super(XXXX,self).__init__(url_map)
self.regex = args[0]
3.添加至app
# 創建Flask對象
app = Flask(__name__)
app.url_map.converters['re'] = XXXX
# 視圖入口
if __name__ == "__main__":
app.run(debug=True) # 調試模式
2.傳參
- 在@app.route(‘/<>’)路由中添加可變參數:
<id>
- 規定參數類型:
<int:id>
- 引用正則:
<re('[a-z]'):id>
3.返回JSON數據
- 導入json數據包
- 調用返回:
json.jumps(json-data)
4.狀態碼
def ret():
return 'data', 200
# 拋出異常,404代表異常類型
def abort_test();
abort(404)
return 'data' # 可以返回字符串,Flask自動封裝爲響應對象
自定義狀態碼視圖
@app.errorhandler(500) # 註冊狀態碼處理函數
def error_test(value):
return '服務器忙...'
5.上下文對象(request.response)
request
sesion
current_app
g
(response)
Flask 封裝request和response爲全局對象
request方法:
方法 | 解釋 |
---|---|
args | 一個包含解析過的查詢字符串( URL 中問號後的部分)內容的 MultiDict |
form | 一個包含解析過的從 POST 或 PUT 請求發送的表單對象的 MultiDict 。請注意上傳的文件不會在這裏,而是在 files 屬性中 |
value | 一個包含 form 和 args 全部內容的 CombinedMultiDict |
cookies | 一個包含請求中傳送的所有 cookie 內容的 dict |
headers | 進入請求的標頭存爲一個類似字典的對象 |
files | 一個包含 POST 和 PUT 請求中上傳的文件的 MultiDict. 包含save()方法 |
method | 當前請求的 HTTP 方法 |
如下參考完整url信息 | http://www.example.com/myapplication/page.html?x=y |
path | /page.html |
script_root | /myapplication |
base_url | http://www.example.com/myapplication/page.html |
url | http://www.example.com/myapplication/page.html?x=y |
url_root | http://www.example.com/myapplication/ |
response方法:
方法 | 解釋 |
---|---|
headers | Headers 對象用於設置響應的頭信息 |
status | 用於設置響應狀態描述 |
status_code | 整數,用於設置響應狀態碼 |
mimetype | 用於設置響應的MIME類型 |
set_cookie() | 設置cookie |
示例:
response = make_response('顯示文字') # 創建response對象
response.set_cookie(key, value) # 設置cookie
request.headers.get('User-Agent') # 獲取請求頭中內容
session['key'] = value # 設置session
session.get('key') # 獲取session
6.應用上下文current_app和變量g
current_app 可以獲取當前app所在環境信息(ip,內存等)
current_app.name # 獲取應用名稱
current_app.test_value='value' # 利用應用上下文存取變量
g.name='abc' # 臨時性全局變量
*手動創建應用上下文:應用上下文只存在於當前主線程中,額外創建的子線程中需要手動創建
with app.app_context():
other_code_for_you
7.Flask擴展包
- Flask-SQLalchemy:操作數據庫;
- Flask-Migrate:管理遷移數據庫;
- Flask-Mail:郵件;
- Flask-WTF:表單;
- Flask-Bable:提供國際化和本地化支持,翻譯;
- Flask-Script:插入腳本;
- Flask-Login:認證用戶狀態;
- Flask-OpenID:認證;
- Flask-RESTful:開發REST API的工具;
- Flask-Bootstrap:集成前端Twitter Bootstrap框架;
- Flask-Moment:本地化日期和時間;
8.Flask_script擴展
from flask import Flask
from flask_script import Manager # 導入
app = Flask(__name__)
manager = Manager(app) # 註冊
@app.route('/')
def index():
return '牀前明月光'
if __name__ == "__main__":
manager.run() # 使用
9.Flask-Script插件
添加管理功能:
pip install Flask-Script # 安裝
from flask_script import Manager
app = Flask(__name__)
...
manager = Manager(app)
...
manager.run()
python app.py runserver # 運行
測試的命令行環境(調試):
python app.py shell
... # 修改調試上下文(app.app_context()返回current_app)
... # app.test_request_ctx()
… 上下文對象存儲於棧結構中:先進後出,後進先出
10.模板
模板語言
代碼塊:
{{ }}
邏輯代碼:
{% %}
也可以使用過濾器{{ loop.index }} # 返回循環索引,從1開始
{{ loop.cycle('1', 'a', 'c') }} # 返回cycle中作爲索引
禁止解析:
{% raw %} <script>js處理</script> {% raw %}
過濾器:
{{ variable | filter_name(*args) }} # *args在沒有條件的情況下可以省略
示例:
{{ 111 | float }}
{{ 111.11 | int }}
{{ [python , flask] | join(',')}}
{{ '123' | length }}
{{ 3.1415 | round(2) }} # 四捨五入
{{ 4.22 | round(1, 'common') }} # 四捨五入
{{ 4.28 | round(1, 'floor') }} # 舍位
{{ 4.22 | round(1, 'ceil') }} # 進位
{{ {'key': 'value'} | tojson }} # json輸出
{{ 'abcdefg' | truncate(3, True) }} # 截取,True代表包含空格
{{ False_args | default('Treu_args, True') }} # 變量爲假時,替換爲default值
{{ '%s is %d' | format('name',17) }} # 格式化輸出
{{ ' hello world ' | trim }} # 去掉首尾空格
{{ '<em>hello</em>' | striptags }} # 渲染前去掉HTML標籤
- title upper lower capitalize等
自定義過濾器
app.jinjia_env.filters['key'] = filter_function # 註冊過濾器函數
模板渲染
模板文件放在項目根目錄下templates目錄下
render_template('index.html')
模板傳參
render_template('index.html', name=name, pwd=pwd)
11.宏
實現HTML代碼重用(類似於代碼公共部分抽取,繼承)
{% macro func(name,label,value='',type='text') %}
<input type="{{type}}" name="{{name}}"
value="{{value|escape}}" class="form-control">
{% endmacro %}
調用:
func(name, 'username') # 當前文件調用
封裝爲文件:
{% macro function() %}
<div class="form-group">
<input type="{{type}}" name="{{name}}"
value="{{value|escape}}" class="form-control">
</div>
{% endmacro %}
其他文件調用:
{% import 'macro.html' as func %}
{% func.function() %}
12.模板繼承
調用父類模板內容
{% block content %}
{% super() %}
... // 自定義內容
{% endblock %}
13.Flask 特有變量和函數
url_for() # 獲取視圖函數對應的url
redirect(url_for('views_function')) # 重定向(發送兩次請求,地址欄改變)
設置: app.config['aaa']='xxx' 獲取: {{config.aaa}} # 作爲配置文件信息使用
設置: session['aaa']='xxx' 獲取: {{session.get('aaa')}}
flash('a')=b # 應用中設置
{%for message in get_flashed_messages()%}
{{message}} // 獲取輸入框提示信息等
{%endfor%}
14.Form
1.WTF–簡化form生成以及驗證過程
常用字段:
表單內容驗證函數:
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField
from wtforms.validators import DataRequired,EqualTo
class Login(FlaskForm):
username = StringField(lable='用戶名', validators=[DataRequired()])
password = PasswordField(label='密碼', validators=[DataRequired(), EqualTo('ps2','err')])
submit = SubmitField('提交')
# u(原生字符)可以使用如下代碼替代:
app.config['SECRET_KEY'] = 'abc' # 非對稱加密公鑰
@app.route('/register')
def register():
form = login() # 創建對象
return render_template('register.html', form=form)
<form method="post" action="">
{{ form.csrf_token() }}
{{ form.username.label }}
<p>{{ form.us }}</p>
{{ form.password.label }}
<p>{{ form.ps }}</p>
<p>{{ form.submit() }}</p>
{% for x in get_flashed_messages() %}
{{ x }}
{% endfor %}
</form>
@app.route('/',methods=['GET','POST'])
def index():
form = Login()
if form.validate_on_submit(): # 表單提交有效性驗證
name = form.username.data # 兩種獲取方式
pswd = request.form['password']
return redirect(url_for("success"))
else:
if request.method=='POST':
flash(u'信息有誤,請重新輸入!')
print form.validate_on_submit()
return render_template('index.html',form=form)
2.原生
from flask import Flask
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST']) # 默認爲GET請求(渲染頁面),需要添加POST(提交表單)
def login():
if request.method == 'POST':
# 第二次請求使用POST
username = requst.forms['username'] # 表單中無action=''提交路徑,默認返回當前頁面
# 第一次訪問,渲染表單頁面
return render_template('login.html', method=request.method)
@app.route('/login_handle', methods=['POST']) # 一般提交至第二個視圖處理,默認爲GET請求,需要添加POST
def login_handle():
username = request.forms['username'] # 獲取表單數據
return ...
if __name__ == '__main__':
app.run()
15.SQLALchemy
Flask中關係型擴展,用來操作數據庫
1.配置:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://user_name:[email protected]:3306/database_name'
2.常用字段類型:
字段約束類型:
- 主鍵約束:唯一且非空
- 唯一約束:可以爲null,但非null不可重複
- 非空約束:not null
- 外鍵約束:區關聯主鍵,或者null
3.常用列選項:
4.常用關係選項:
一對多
class Role(db.Model):
...
# 關鍵代碼
us = db.relationship('User', backref='role', lazy='dynamic')
...
class User(db.Model):
...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
backref
爲類User申明新屬性的方法
lazy
決定了什麼時候SQLALchemy從數據庫中加載數據,如果設置爲子查詢方式subquer
,則會在加載完User對象後,就立即加載與其關聯的對象,這樣會讓總查詢數量減少,但如果返回的條目數量很多,就會比較慢,另外,也可以設置爲動態方式dynamic
,這樣關聯對象會在被使用的時候再進行加載,並且在返回前進行過濾,如果返回的對象數很多,或者未來會變得很多,那最好採用這種方式
多對多
registrations = db.Table('registrations',
db.Column('student_id', db.Integer, db.ForeignKey('students.id')),
db.Column('course_id', db.Integer, db.ForeignKey('courses.id'))
)
class Course(db.Model):
...
class Student(db.Model):
...
classes = db.relationship('Course',secondary=registrations,
backref='student',
lazy='dynamic')"
registrations
爲格外創建的關聯表
5.創建表以及插入數據
db.create_all()
data1 = Student(name = '1')
db.session.add(data1) # 或者 db.session.add_all([data1, data2])
db.session.commit()
6.查詢
常用SQLAlchemy查詢過濾器
常用查詢執行器
邏輯與:and_()
邏輯或:or_()
邏輯非:not_()
7.刪除查詢對象
stu1 = Student.query.first()
db.session.delete(stu1)
db.session.commit()
8.更新數據
stu1 = Student.query.first()
stu1.name = 'new_name'
db.session.commit()
16.數據庫遷移flask-migrate
準備:
migrate = Manager(app, db)
manager = Manager(app)
manager.add_command('db', MiagrateCommand) # 註冊至flask-script,方便在命令行管理
操作:
python app.py db init # 初始化 # db 爲add_command()中設置的名稱
python app.py db migrate -m'版本名' # 創建遷移文件,版本參數可以省略
python app.py db upgrade # 遷移
python app.py db history # 歷史版本
python app.py db downgrade 版本號 # 回滾
傳入shell對象字典,避免每次shell操作導入
def make_shell_context():
return dict(app=app, db=db,...)
manager.add_command('shell', Shell(make_context=make_shell_context))
17.發送郵件flask-mail
1.配置:(服務器,端口,安全套接字層/傳輸安全層協議,郵箱名,密碼等)
app.config['MAIL_SERVER'] = 'smtp.126.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME']=
app.config['MAIL_PASSWORD']=
app.config['MY_MAIL_SENDER'] = #發送者
app.config['MY_MAIL_TO']= # 接收者
2.註冊:
mail= Mail(app)
3.設置消息:
msg = Message(subject, sender='', recipientes=['to_1'], ...)
msg.body='' 或者 msg.html=''
4.發送:
mail.send(msg)
18.flask-bootstrap
bootstrap = Bootstrap(app)
19.flask-Moment(未完成)
moment = Moment(app)
moment.include_moment()
20.Blueprint
將項目文件模塊化
1.創建藍圖對象
login = Blueprint('login', __name__,static_folder='', template_folder='')
# 同名文件,系統默認使用項目下默認的templates下文件,可以使用相對路徑避免此問題
2.註冊路由,指定靜態文件夾,模板文件夾
@login.route('/')
def login_index():
return 'login_index'
@login.route('/handle)
def login_handle():
return 'login_handle'
3.在應用對象上註冊藍圖
app.register_blueprint(login, url_prefix='/login')
static_url_path
:可以爲當前藍圖靜態文件目錄指定一個別名
使用url_for
查詢視圖函數:url_for('login.login_index')