python flask框架(上)

flask文檔
flask最佳實踐

已經解釋的非常詳細了,我這里只把我關注的點以我的理解記錄一下。

一:程序的基本結構

1. 初始化
2. 路由和視圖函數
  • flask使用route裝飾器把一個函數綁定到對應的 URL 上,把修飾的函數注冊為路由
  • URL 使用尖括號 <variable_name> , flask將這個部分作為命名參數傳遞到你的函數。可以給該參數定義轉換器實現(xiàn)類型轉換。
    轉換器又:int,float,path
@app.route('/user/<username>')
def show_user_profile(username):
    return 'User %s' % username
@app.route('/post/<int:post_id>')
def show_post(post_id):
    return 'Post %d' % post_id
3. 程序和請求的上下文
  • Flask使用在 Flask 中由全局的 request 對象來提供這些信息客戶端交互信息。

  • Flask 從客戶端收到請求時,要先讓視圖函數能訪問一些對象,這樣才能處理請求。例如request對象封裝了客戶端發(fā)送的 HTTP 請求。

  • Flask 使用上下文臨時把某些對象變?yōu)槿挚稍L問。

  • 在 Flask 中有兩種上下文:程序上下文和請求上下文


    flask上下文
  • Flask 在分發(fā)請求之前激活(或推送)程序和請求上下文,請求處理完成后再將其刪除

  • 在程序實例上調用 app.app_context() 可獲得一個程序上 下文。

  • Flask 中的某些對象是全局對象,但卻不是通常的那種。這些對象實際上是特定環(huán)境的局部對象的代理。雖然很拗口,但實際上很容易理解。

  • 想象一下處理線程的環(huán)境。一個請求傳入,Web 服務器決定生成一個新線程( 或者別的什么東西,只要這個底層的對象可以勝任并發(fā)系統(tǒng),而不僅僅是線程)。 當 Flask 開始它內部的請求處理時,它認定當前線程是活動的環(huán)境,并綁定當前的應用和 WSGI 環(huán)境到那個環(huán)境上(線程)。它的實現(xiàn)很巧妙,能保證一個應用調用另一個應用時不會出現(xiàn)問題。

  • 所以,這對你來說意味著什么?除非你要做類似單元測試的東西,否則你基本上可以完全無視它。你會發(fā)現(xiàn)依賴于一段請求對象的代碼,因沒有請求對象無法正常運行。解決方案是,自行創(chuàng)建一個請求對象并且把它綁定到環(huán)境中。單元測試的最簡單的解決方案是:用 <tt class="xref py py-meth docutils literal" style="font-family: Consolas, Menlo, "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", monospace; font-size: 0.9em; background-color: rgb(251, 251, 251); color: rgb(34, 34, 34); font-weight: bold; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: white;">test_request_context()</tt> 環(huán)境管理器。結合 <cite>with</cite> 聲明,綁定一個測試請求,這樣你才能與之交互

4. 請求調度
  • 程序收到客戶端發(fā)來的請求時,要找到處理該請求的視圖函數。為了完成這個任務,F(xiàn)lask 會在程序的 URL 映射中查找請求的 URL。URL 映射是 URL 和視圖函數之間的對應關系。 Flask 使用 app.route 修飾器或者非修飾器形式的 app.add_url_rule() 生成映射。
  • URL 映射中的 HEAD、Options、GET 是請求方法,由路由進行處理。Flask 為每個路由都指 定了請求方法,這樣不同的請求方法發(fā)送到相同的 URL 上時,會使用不同的視圖函數進 行處理。
5. 請求鉤子
  • 有時需要在處理請求之前或之后執(zhí)行代碼。例如,認證發(fā)起請求的用戶。為了避免在每個視圖函數中都使用重復的代碼, Flask 提供了注冊通用函數的功能,注冊的函數可在請求被分發(fā)到視圖函數之前或之后調用。這種程序叫做鉤子函數。
  • 請求鉤子使用修飾器實現(xiàn)
  • flask支持以下幾種鉤子
    • before_first_request:注冊一個函數,在處理第一個請求之前運行
    • before_request:注冊一個函數,在每次請求之前運行
    • after_request:注冊一個函數,如果沒有未處理的異常拋出,在每次請求之后運行
    • teardown_request:注冊一個函數,即使有未處理的異常拋出,也在每次請求之后運行。
  • 在請求鉤子函數和視圖函數之間共享數據一般使用上下文全局變量 g,例如,before_ request 處理程序可以從數據庫中加載已登錄用戶,并將其保存到 g.user 中。隨后調用視 圖函數時,視圖函數再使用 g.user 獲取用戶。
6. 響應
  • Flask 視圖函數一般返回一個 Response 對象。make_response() 函數可接受 1 個、2 個或 3 個參數(和視圖函數的返回值一樣),并返回一個 Response 對象。
from flask import make_response
     @app.route('/')
     def index():
         response = make_response('<h1>This document carries a cookie!</h1>')
         response.set_cookie('answer', '42')
         return response
  • 重定向是一種特殊的響應,響應內容是 URL,而不是包含 HTML 代碼的字符串。瀏覽器收到 這種響應時,會向重定向的 URL 發(fā)起 GET 請求,顯示頁面的內容。
  • 重定向響應可以使用 3 個值形式的返回值生成,也可在 Response 對象中設定。不過,由于使用頻繁,F(xiàn)lask 提 供了 redirect() 輔助函數,
from flask import redirect
     @app.route('/')
     def index():
return redirect('http://www.example.com')
  • 可以使用redirect() 輔助函數, 生成 HTTP 重定向響應。redirect() 函數的參數是重定向的 URL,推薦使用 url_for() 生成 URL,因為這 個函數使用 URL 映射生成 URL,從而保證 URL 和定義的路由兼容,而且修改路由名字后 依然可用。
  • url_for() 函數的第一個且唯一必須指定的參數是端點名,即路由的內部名字。默認情 況下,路由的端點是相應視圖函數的名字。
  • 重定向時請求數據會request上下文的內容會丟失,因為重定向相當于另一個請求,這時程序可以把數據存儲在session中,在請求之間“記住”數據。session是一種私有存 儲,存在于每個連接到服務器的客戶端中。默認情況下,session保存在客戶端 cookie 中
from flask import Flask, render_template, session, redirect, url_for
     @app.route('/', methods=['GET', 'POST'])
     def index():
         form = NameForm()
         if form.validate_on_submit():
             session['name'] = form.name.data
             return redirect(url_for('index'))
         return render_template('index.html', form=form, name=session.get('name'))

flask擴展

社區(qū)成員開發(fā)了大量不同用途的flask擴展,下面介紹如何把擴展整合到程序中

  1. 使用pip安裝flask擴展
  2. 在程序中使用from flask.ext.script import Manager flask.ext模塊導入該擴展
  • 專為 Flask 開發(fā)的擴展都暴漏在 flask.ext 命名空間下

二:模版

  • 默認情況下,F(xiàn)lask 在程序文件夾中的 templates 子文件夾中尋找模板
  • flask支持很多模版引擎, render_template 函數把 Jinja2模板引擎集成到了程序中
  • render_template 函 數的第一個參數是模板的文件名。隨后的參數都是鍵值對,表示模板中變量對應的真實值
from flask import Flask, render_template # ...
     @app.route('/user/<name>')
     def user(name):
         return render_template('user.html', name=name)
1. 變量
  • 在模板中使用的{{ name }}結構表示一個變量,它是一種特殊的占位符,告訴模板引擎這個位置的值從渲染模板時使用的數據中獲取
  • 可以使用過濾器修改變量,過濾器名添加在變量名之后,中間使用豎線分隔
  • Jinja2 提供的部分常用過濾器:


    Jinja2 提供的部分常用過濾器
2. jinja2控制結構
  • Jinja2 提供了多種控制結構,可用來改變模板的渲染流程
條件控制語句
{% if user %}
Hello, {{ user }}!
{% else %}
Hello, Stranger!
{% endif %}

for循環(huán)
<ul>
{% for comment in comments %}
<li>{{ comment }}</li> {% endfor %}
</ul>

引入別的文件
{% include 'common.html' %}
  • 需要在多處重復使用的模板代碼片段可以寫入單獨的文件,再包含在所有模板中,以避免 重復:
  • 模版繼承
    base.html
   <html>
     <head>
{% block head %}  //聲明一個代碼塊
<title>{% block title %}{% endblock %} - My Application</title> {% endblock %}
     </head>
     <body>
{% block body %}
{% endblock %} </body>
</html>
{% extends "base.html" %}  聲明這個模板衍生自 base.html。
{% block title %}Index{% endblock %} {% block head %}   //覆蓋父類代碼塊
         {{ super() }} 
         <style>
         </style>
{% endblock %}
{% block body %} <h1>Hello, World!</h1> {% endblock %}
推薦使用flask-bootstrap框架
  • Flask-Bootstrap 中的基模板提供了一個網頁框架,引入了 Bootstrap 中的所有 CSS 和JavaScript 文件。
3. 自定義錯誤顯示頁面
  • Flask 允許程序使用基于模板的自定義錯誤頁面
4.鏈接
  • Flask 提供了 url_for() 輔助函數,它可以使用程序 URL 映射中保存 的信息生成 URL
  • url_for() 函數最簡單的用法是以視圖函數名(或者 app.add_url_route() 定義路由時使用 的端點名)作為參數,返回對應的 URL。
  • 使用 url_for() 生成動態(tài)地址時,將動態(tài)部分作為關鍵字參數傳入。例如,url_for ('user', name='john', _external=True) 的返回結果是 http://localhost:5000/user/john。。傳入 url_for() 的關鍵字參數不僅限于動態(tài)路由中的參數。函數能將任何額外參數添加到 查詢字符串中,例如,url_for('index', page=2) 的返回結果是 /?page=2。
5.靜態(tài)文件
  • 默認設置下,F(xiàn)lask 在程序根目錄中名為 static 的子目錄中尋找靜態(tài)文件
{% block head %}
{{ super() }}
<link rel="shortcut icon" href="{{ url_for('static', filename = 'favicon.ico') }}"
type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename = 'favicon.ico') }}"
type="image/x-icon"> {% endblock %}

四:web表單

  • request.form 能獲取 POST 請求中提交的表單數據。
  • Flask-WTF擴展可以把處理 Web 表單的過程變成一 種愉悅的體驗。
1. 跨站請求偽造保護
  • 默認情況下,F(xiàn)lask-WTF 能保護所有表單免受跨站請求偽造(CSRF)的攻擊
  • 為了實現(xiàn) CSRF 保護,F(xiàn)lask-WTF 需要程序設置一個密鑰。Flask-WTF 使用這個密鑰生成加密令牌,再用令牌驗證請求中表單數據的真?zhèn)?/li>
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
  • app.config 字典可用來存儲框架、擴展和程序本身的配置變量。
4.2 表單類
  • 類定義表單中的 一組字段,每個字段都用對象表示。字段對象可附屬一個或多個驗證函數。驗證函數用來 驗證用戶提交的輸入值是否符合要求。
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField from wtforms.validators import Required
class NameForm(Form):
name = StringField('What is your name?', validators=[Required()]) submit = SubmitField('Submit')

//字段構造函數的第一個參數是把表單渲染成 HTML 時使用的標號
//StringField 構造函數中的可選參數 validators 指定一個由驗證函數組成的列表,在接受 用戶提交的數據之前驗證數據。驗證函數 Required() 確保提交的字段不為空
3.把表單渲染成HTML
  • 表單字段是可調用的,在模板中調用后會渲染成 HTML。
  • Flask-Bootstrap 提供了一個非常高端的輔助函 數,可以使用 Bootstrap 中預先定義好的表單樣式渲染整個 Flask-WTF 表單
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %} <div class="page-header">
<h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1> </div>
{{ wtf.quick_form(form) }} {% endblock %}
  1. 在視圖函數中處理表單
@app.route('/', methods=['GET', 'POST'])
     def index():
         name = None
         form = NameForm() 在視圖函數中創(chuàng)建一個 NameForm 類實例用于表示表單
         if form.validate_on_submit():
             name = form.name.data
             form.name.data = ''
         return render_template('index.html', form=form, name=name)
  1. Flash消息
  • flash() 函數

七:大型程序的結構

import os


basedir = os.path.abspath(os.path.dirname(__file__))
class Config:  #基類 Config 中包含通用配置,子類分別定義專用的配置。
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string' 
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
    FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>' 
    FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')
    @staticmethod
    def init_app(app):
          pass


class DevelopmentConfig(Config):
    DEBUG = True
    MAIL_SERVER = 'smtp.googlemail.com'
    MAIL_PORT = 587
    MAIL_USE_TLS = True
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
      'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')


class TestingConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \
              'sqlite:///' + os.path.join(basedir, 'data-test.sqlite')

class ProductionConfig(Config):
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
              'sqlite:///' + os.path.join(basedir, 'data.sqlite')


config = {
'development': DevelopmentConfig, 'testing': TestingConfig, 'production': ProductionConfig,
'default': DevelopmentConfig }
  • 為了讓配置方式更靈活且更安全,某些配置可以從環(huán)境變量中導入。例如,SECRET_KEY 的值, 這是個敏感信息,可以在環(huán)境中設定,但系統(tǒng)也提供了一個默認值,以防環(huán)境中沒有定義。
  • 配置類可以定義 init_app() 類方法,其參數是程序實例。
2. 藍本blueprint
  • 藍本和程序類似,也可以定義路由。不同的 是,在藍本中定義的路由處于休眠狀態(tài),直到藍本注冊到程序上后,路由才真正成為程序 的一部分。使用位于全局作用域中的藍本時,定義路由的方法幾乎和單腳本程序一樣
  • 藍本可以在單個文件中定義,也可使用更結構化的方式在包中的多個模塊中創(chuàng)建
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
  • 程序的路由保存在包里的 app/main/views.py 模塊中,而錯誤處理程序保存在 app/main/ errors.py 模塊中。導入這兩個模塊就能把路由和錯誤處理程序與藍本關聯(lián)起來

參考鏈接:
Flask 文檔

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容