python flask框架(上)

flask文檔
flask最佳實(shí)踐

已經(jīng)解釋的非常詳細(xì)了,我這里只把我關(guān)注的點(diǎn)以我的理解記錄一下。

一:程序的基本結(jié)構(gòu)

1. 初始化
2. 路由和視圖函數(shù)
  • flask使用route裝飾器把一個函數(shù)綁定到對應(yīng)的 URL 上,把修飾的函數(shù)注冊為路由
  • URL 使用尖括號 <variable_name> , flask將這個部分作為命名參數(shù)傳遞到你的函數(shù)??梢越o該參數(shù)定義轉(zhuǎn)換器實(shí)現(xiàn)類型轉(zhuǎn)換。
    轉(zhuǎ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 從客戶端收到請求時,要先讓視圖函數(shù)能訪問一些對象,這樣才能處理請求。例如request對象封裝了客戶端發(fā)送的 HTTP 請求。

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

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


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

  • 在程序?qū)嵗险{(diào)用 app.app_context() 可獲得一個程序上 下文。

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

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

  • 所以,這對你來說意味著什么?除非你要做類似單元測試的東西,否則你基本上可以完全無視它。你會發(fā)現(xiàn)依賴于一段請求對象的代碼,因沒有請求對象無法正常運(yù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)境管理器。結(jié)合 <cite>with</cite> 聲明,綁定一個測試請求,這樣你才能與之交互

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

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

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

二:模版

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


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

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

引入別的文件
{% include 'common.html' %}
  • 需要在多處重復(fù)使用的模板代碼片段可以寫入單獨(dú)的文件,再包含在所有模板中,以避免 重復(fù):
  • 模版繼承
    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 中的基模板提供了一個網(wǎng)頁框架,引入了 Bootstrap 中的所有 CSS 和JavaScript 文件。
3. 自定義錯誤顯示頁面
  • Flask 允許程序使用基于模板的自定義錯誤頁面
4.鏈接
  • Flask 提供了 url_for() 輔助函數(shù),它可以使用程序 URL 映射中保存 的信息生成 URL
  • url_for() 函數(shù)最簡單的用法是以視圖函數(shù)名(或者 app.add_url_route() 定義路由時使用 的端點(diǎn)名)作為參數(shù),返回對應(yīng)的 URL。
  • 使用 url_for() 生成動態(tài)地址時,將動態(tài)部分作為關(guān)鍵字參數(shù)傳入。例如,url_for ('user', name='john', _external=True) 的返回結(jié)果是 http://localhost:5000/user/john。。傳入 url_for() 的關(guān)鍵字參數(shù)不僅限于動態(tài)路由中的參數(shù)。函數(shù)能將任何額外參數(shù)添加到 查詢字符串中,例如,url_for('index', page=2) 的返回結(jié)果是 /?page=2。
5.靜態(tài)文件
  • 默認(rèn)設(shè)置下,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 請求中提交的表單數(shù)據(jù)。
  • Flask-WTF擴(kuò)展可以把處理 Web 表單的過程變成一 種愉悅的體驗。
1. 跨站請求偽造保護(hù)
  • 默認(rèn)情況下,F(xiàn)lask-WTF 能保護(hù)所有表單免受跨站請求偽造(CSRF)的攻擊
  • 為了實(shí)現(xiàn) CSRF 保護(hù),F(xiàn)lask-WTF 需要程序設(shè)置一個密鑰。Flask-WTF 使用這個密鑰生成加密令牌,再用令牌驗證請求中表單數(shù)據(jù)的真?zhèn)?/li>
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
  • app.config 字典可用來存儲框架、擴(kuò)展和程序本身的配置變量。
4.2 表單類
  • 類定義表單中的 一組字段,每個字段都用對象表示。字段對象可附屬一個或多個驗證函數(shù)。驗證函數(shù)用來 驗證用戶提交的輸入值是否符合要求。
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')

//字段構(gòu)造函數(shù)的第一個參數(shù)是把表單渲染成 HTML 時使用的標(biāo)號
//StringField 構(gòu)造函數(shù)中的可選參數(shù) validators 指定一個由驗證函數(shù)組成的列表,在接受 用戶提交的數(shù)據(jù)之前驗證數(shù)據(jù)。驗證函數(shù) Required() 確保提交的字段不為空
3.把表單渲染成HTML
  • 表單字段是可調(diào)用的,在模板中調(diào)用后會渲染成 HTML。
  • Flask-Bootstrap 提供了一個非常高端的輔助函 數(shù),可以使用 Bootstrap 中預(yù)先定義好的表單樣式渲染整個 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. 在視圖函數(shù)中處理表單
@app.route('/', methods=['GET', 'POST'])
     def index():
         name = None
         form = NameForm() 在視圖函數(shù)中創(chuàng)建一個 NameForm 類實(shí)例用于表示表單
         if form.validate_on_submit():
             name = form.name.data
             form.name.data = ''
         return render_template('index.html', form=form, name=name)
  1. Flash消息
  • flash() 函數(shù)

七:大型程序的結(jié)構(gòu)

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)境變量中導(dǎo)入。例如,SECRET_KEY 的值, 這是個敏感信息,可以在環(huán)境中設(shè)定,但系統(tǒng)也提供了一個默認(rèn)值,以防環(huán)境中沒有定義。
  • 配置類可以定義 init_app() 類方法,其參數(shù)是程序?qū)嵗?/li>
2. 藍(lán)本blueprint
  • 藍(lán)本和程序類似,也可以定義路由。不同的 是,在藍(lán)本中定義的路由處于休眠狀態(tài),直到藍(lán)本注冊到程序上后,路由才真正成為程序 的一部分。使用位于全局作用域中的藍(lán)本時,定義路由的方法幾乎和單腳本程序一樣
  • 藍(lán)本可以在單個文件中定義,也可使用更結(jié)構(gòu)化的方式在包中的多個模塊中創(chuàng)建
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
  • 程序的路由保存在包里的 app/main/views.py 模塊中,而錯誤處理程序保存在 app/main/ errors.py 模塊中。導(dǎo)入這兩個模塊就能把路由和錯誤處理程序與藍(lán)本關(guān)聯(lián)起來

參考鏈接:
Flask 文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 22年12月更新:個人網(wǎng)站關(guān)停,如果仍舊對舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,401評論 22 257
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,555評論 19 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong閱讀 22,942評論 1 92
  • ? ??在第1章,我們已經(jīng)了解了Flask的基本知識,如果想要進(jìn)一步開發(fā)更復(fù)雜的Flask應(yīng)用,我們就得了解F...
    懵懂_傻孩紙閱讀 3,106評論 0 4
  • 這幾天想學(xué)新東西,就看了flask框架,本身對python不太了解,網(wǎng)上的很多教程看了,總是在某些地方卡住。翻到一...
    易木成華閱讀 2,399評論 0 11

友情鏈接更多精彩內(nèi)容