Flask-1-03-HelloWorld

Flask程序運行過程:

全部Flask程序必須有一個程序實例html

Flask調用視圖函數後,會將視圖函數的返回值做爲響應的內容,返回給客戶端。通常狀況下,響應內容主要是字符串和狀態碼。python

當客戶端想要獲取資源時,通常會經過瀏覽器發起HTTP請求。此時,Web服務器使用WSGI(Web Server Gateway Interface)協議,把來自客戶端的全部請求都交給Flask程序實例。WSGI是爲 Python 語言定義的Web服務器和Web應用程序之間的一種簡單而通用的接口,它封裝了接受HTTP請求、解析HTTP請求、發送HTTP,響應等等的這些底層的代碼和操做,使開發者能夠高效的編寫Web應用。正則表達式

程序實例使用Werkzeug來作路由分發(URL請求和視圖函數之間的對應關係)。根據每一個URL請求,找到具體的視圖函數。 在Flask程序中,路由的實現通常是經過程序實例的route裝飾器實現。route裝飾器內部會調用add_url_route()方法實現路由註冊。flask

調用視圖函數,獲取響應數據後,把數據傳入HTML模板文件中,模板引擎負責渲染響應數據,而後由Flask返回響應數據給瀏覽器,最後瀏覽器處理返回的結果顯示給客戶端。瀏覽器

 

瞭解一門框架從HelloWorld開始


 

新建文件helloworld.py:

# 導入Flask類
from flask import Flask

#Flask類接收一個參數__name__
app = Flask(__name__)

# 裝飾器的做用是將路由映射到視圖函數index
@app.route('/')
def index():
    return 'Hello World'

# Flask應用程序實例的run方法啓動WEB服務器
if __name__ == '__main__':
    app.run()

這些就已經足夠了,那麼咱們來運行一下helloworld.py(到保存helloworld.py的路徑下):

$ cd /home/python/code
$ python helloworld.py

可以看出服務器已經啓動,地址是127.0.0.1 端口:5000,這時候去瀏覽器訪問查看結果

初始化參數:

  1. import_name: 模塊名,flask以這個模塊所在的目錄爲總目錄,默認這個目錄中的static爲靜態目錄,templates爲模板目錄
  2. static_url_path:訪問靜態資源的url前綴, 默認值是static
  3. static_folder: 默認‘static’ 靜態文件的目錄
  4. template_folder: 默認‘templates’ 模板文件的目錄
...

app = Flask(__name__,
            static_url_path="/python",  # 訪問靜態資源的url前綴, 默認值是static
            static_folder="static",  # 靜態文件的目錄,默認就是static
            template_folder="templates",  # 模板文件的目錄,默認是templates
            )

...

配置參數

配置參數默認有3中方式:

  • app.config.from_pyfile(「config.cfg」)   從文件導入
  • app.config.from_object()  從對象中導入服務器

  • app.config.from_envvar()  從環境變量中導入(應該沒有人願意用)

1. app.config.from_pyfile(「config.cfg」) :在項目的根目錄下建立一個config.cfg文件

 1 from flask import Flask
 2 
 3 app = Flask(__name__,
 4             static_url_path="/python",  # 訪問靜態資源的url前綴, 默認值是static
 5             static_folder="static",  # 靜態文件的目錄,默認就是static
 6             template_folder="templates",  # 模板文件的目錄,默認是templates
 7             )
 8 
 9 # 配置參數的使用方式
10 # 1. 使用配置文件
11 app.config.from_pyfile("config.cfg")
12 
13 
14 @app.route("/")
15 def index():
16     """定義的視圖函數"""
17     return "helloworld"
18 
19 
20 if __name__ == '__main__':
21     # 啓動flask程序
22     app.run()
# config.cfg 文件
DEBUG = True

目錄結構

這樣你從新運行一下app

2.app.config.from_object()  從對象中導入

  建立一個類,來定義類屬性爲配置項框架

# coding:utf-8

from flask import Flask

app = Flask(__name__,
            static_url_path="/python",  # 訪問靜態資源的url前綴, 默認值是static
            static_folder="static",  # 靜態文件的目錄,默認就是static
            template_folder="templates",  # 模板文件的目錄,默認是templates
            )

# 2. 使用對象配置參數
class Config(object):
    DEBUG = True
# 使用方法加載設置的配置
app.config.from_object(Config)


@app.route("/")
def index():
    """定義的視圖函數"""
    return "hello world"


if __name__ == '__main__':
    # 啓動flask程序
    app.run()

3.直接操做config對象

from flask import Flask

app = Flask(__name__,
            static_url_path="/python",  # 訪問靜態資源的url前綴, 默認值是static
            static_folder="static",  # 靜態文件的目錄,默認就是static
            template_folder="templates",  # 模板文件的目錄,默認是templates
            )

# 3. 直接操做config的字典對象
app.config["DEBUG"] = True


@app.route("/")
def index():
    return "hello flask"


if __name__ == '__main__':
    # 啓動flask程序
    app.run()
   

讀取配置參數

  1.若是你在當前能訪問到app的狀況下函數

    app.config.get("DEBUG")post

  2.若是你沒法拿到app這個對象時,你只須要導入current_app,也是能夠拿到配置信息的

    current_app.config.get("DEBUG")

from flask import Flask, current_app

@app.route("/")
def index():
    """定義的視圖函數"""
    # 讀取配置參數
    # 1. 直接從全局對象app的config字典中取值
    # print(app.config.get("ITCAST"))
    # 2. 經過current_app獲取參數
    # print(current_app.config.get("ITCAST"))

    return "hello flask"

app.run 參數

if __name__ == '__main__':
    # 啓動flask程序
    # app.run()
    app.run(host="0.0.0.0", port=5000, debug=True) # port指定的端口,debug 是惟一能夠指定在這裏的配置項

你在開發的狀態下,若是局域網中不須要別的主機訪問,你能夠不指定(host),若是你想在同一局域網中,別的主機也能夠訪問到,而且你本身還想以迴環地址(127.0.0.1)訪問的話就能夠指定爲‘0.0.0.0’

擴展: 0.0.0.0  

IPV4中,0.0.0.0地址被用於表示一個無效的,未知的或者不可用的目標。 
* 在服務器中,0.0.0.0指的是本機上的全部IPV4地址,若是一個主機有兩個IP地址,192.168.1.1 和 10.1.2.1,而且該主機上的一個服務監聽的地址是0.0.0.0,那麼經過兩個ip地址都可以訪問該服務。 
* 在路由中,0.0.0.0表示的是默認路由,即當路由表中沒有找到徹底匹配的路由的時候所對應的路由。

用途總結:

    • 當一臺主機尚未被分配一個IP地址的時候,用於表示主機自己。(DHCP分配IP地址的時候)
    • 用做默認路由,表示」任意IPV4主機」。
    • 用做服務端,表示本機上的任意IPV4地址。

如今頁面基本是能夠展現了,定義url的規則咱們是經過裝飾器來添加 [ @app.route() ],那麼若是我有不少的頁面,我想直觀的查看一下具體都定義了哪些,咱們這裏就能夠經過:app.url_map 來查看

from flask import Flask, current_app

app = Flask(__name__,
            static_url_path="/python",  # 訪問靜態資源的url前綴, 默認值是static
            static_folder="static",  # 靜態文件的目錄,默認就是static
            template_folder="templates",  # 模板文件的目錄,默認是templates
            )

class Config(object):
    DEBUG = True

app.config.from_object(Config)


@app.route("/")
def index():
    """定義的視圖函數"""
    return "hello flask"


if __name__ == '__main__':
    # 啓動flask程序
    print(app.url_map) # 打印路由的詳情
    app.run()
    

返回結果

(Flask_py) python@python-VirtualBox:~/code$ python hello.py 
# 首先'/' 是咱們index定義的路由規則
# (HEAD, OPTIONS, GET)能夠經過元組中這三種方式訪問
# index是指定的視圖函數
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,  
# /python/<filename> 這是訪問靜態頁面的路由規則
# (HEAD, OPTIONS, GET)默認的訪問方式
# static 靜態資源
 <Rule '/python/<filename>' (HEAD, OPTIONS, GET) -> static>])  
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat

這裏咱們也能夠經過訪問方式來作一些限制性的功能:

好比指定一個視圖,只能經過post方式請求

這裏咱們定義一個視圖 指定訪問方式爲POST

...

@app.route('/post_only', methods=['POST']) def post_only(): return 'post method page'
...

返回結果:這裏能夠看出爆了一個405的狀態碼。DEBUG給咱們爆出的錯誤是GET這種請求方式是不容許的

這裏咱們將GET請求方式也添加到列表中,查看一下是否能夠訪問

...

@app.route('/post_only', methods=['GET','post']) def post_only(): return 'post method page'
...

經過返回的結果能夠看出,已經能夠訪問,而且返回了咱們的響應信息

經過請求方式,咱們能夠的到一些限制,那麼咱們若是定義一樣的路由規則,它又會有怎樣的功能呢?

首先以相同的路徑相同的訪問方式咱們來查看一下會產生什麼樣的結果

# 這裏咱們有兩個視圖分別爲hello一、hello2
@app.route('/hello')
def hello1():
    return 'This is a hello 1'

@app.route('/hello')
def hello2():
    return 'This is a hello 2'

返回結果:頁面展現咱們能夠看出hello2這個視圖函數並無執行,可是經過【app.url_map】咱們能夠看出兩個視圖都在集合當中。

 <Rule '/hello' (HEAD, OPTIONS, GET) -> hello1>,
 <Rule '/hello' (HEAD, OPTIONS, GET) -> hello2>,

很明顯,它們兩個路徑規則和訪問方式,都是相同的,因此當匹配到第一個的時候,就不會在往下執行,那麼接下來,咱們給hello1指定POST請求方式,hello2指定GET請求方式,會返回怎樣的結果呢?

# 這裏咱們分別給hello一、hello2設置了請求方式
@app.route('/hello', methods=['POST'])
def hello1():
    return 'This is a hello 1'

@app.route('/hello', methods=['GET'])
def hello2():
    return 'This is a hello 2'

返回結果:

雖然訪問的路徑是相同的,可是請求方式的不一樣,也是能夠幫咱們限制想要訪問的視圖

 這裏兩個函數用了一個路徑,反之一個函數使用兩個路徑那麼也應該是能夠的

# 定義了一個視圖爲test
@app.route('/test1')
@app.route('/test2')
def test():
    return 'two routes are used for one page'

經過返回結果能夠看出,返回的是同一個頁面

在路徑當中重定向是很是常見的事情,這裏咱們也簡單的介紹一下

這裏就用到redirect()

# 導入redirect來實現頁面重定向
from flask import Flask, current_app, redirect 

...

@app.route("/")
def index():
    """定義的視圖函數"""
    return "index page"

# 建立一個login視圖,當執行完畢後直接返回到index頁面
@app.route('/login')
def login():
    # 定義index視圖的路徑
    url = '/'
    return redirect(url)    
...

返回結果:訪問127.0.0.1:5000/login頁面

 這裏有一個隱患在裏面,若是有一天,咱們認爲index視圖的路徑 '/' 不太適合了,想更改成'/index',那麼項目裏全部跳轉到index的頁面就須要所有改變,這樣就會給咱們程序帶來隱患,那麼咱們找到一個能夠反向解析的方法,只要這個視圖函數還在,無論改變什麼路徑,咱們後續跳轉頁面都不須要更改,那麼就須要使用 url_for('須要跳轉的函數名') 

# 優化代碼,使用反向解析來實現跳轉到 index 頁面
from flask import Flask, current_app, redirect, url_for
...

@app.route("/")  # 當這裏路徑更改以後,下面login視圖中的地址也不須要改變
def index():
    return "index page"

@app.route('/login')
def login():
    url = url_for('index')
    return redirect(url)
...

返回結果:

以前咱們一直都是用寫死的方式,來定義路由規則,這確定是不能知足咱們的開發需求:

如何動態的設置一個路由規則呢?

轉換器:Flask默認給咱們指定了3種,使用方法以下:

int 接受整數
float 接收浮點數
path 和默認的相同,但也接受斜線
# 這裏指定int,尖括號中冒號後面的內容是動態的
@app.route('/user/<int:id>')
def user(id):
    return '歡迎id: %d的用戶' %id

 

這裏若是不指定類型,路由傳遞的參數默認當作string處理

# 127.0.0.1:5000/user/hannibal
@app.route('/user/<username>')
def user(username):
    return '歡迎 %s ' %username

 返回結果:

若是這裏爆出:UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128). 點擊這裏

即便是擁有了int、float、string 這些也是不能知足咱們的需求,那麼咱們就須要自定義轉換器,大致的流程是,咱們須要定義一個類來自定義咱們的轉換器,這個類咱們能夠隨便起名,這裏就用RegexConverter(很是重要的一點是這個類須要繼承werkzeug.routing中的BaseConverter這個類),接下來須要將自定義的轉換器添加到Flask的應用中。最後就是函數來使用這個自定義的轉換器,舉個栗子:

from flask import Flask, current_app, redirect, url_for
from werkzeug.routing import BaseConverter  # 咱們須要繼承的轉換器類
app = Flask(__name__)

class RegexConverter(BaseConverter):
    """自定義轉換器類"""
    def __init__(self, url_map, regex):
        # 調用父類的初始化方法 這裏咱們須要將url_map傳給父類
        super(RegexConverter, self).__init__(url_map)
        # 將正則表達式的參數保存到對象的屬性中,flask會去使用這個屬性來進行路由的正則匹配
        self.regex = regex  # 這個就是咱們規定的正則匹配的規則 r'1[34578]\d{9}' self.regex是固定的寫法

# 將自定義的轉換器添加到flask的應用中 
# 這裏咱們向converters這個字典中添加了一個re鍵對應咱們的轉換器,re本身能夠隨便命名
app.url_map.converters['re'] = RegexConverter # 這裏模擬匹配手機號碼 # 127.0.0.1:5000/send/138XXXXXXXX @app.route("/send/<re(r'1[34578]\d{9}'):phone_num>") def send_sms(phone_num): return "send message to %s" % phone_num if __name__ == '__main__': # 查看路由信息 print(app.url_map) # 啓動flask程序 app.run(debug=True)

返回結果:這裏若是你填寫一個不匹配的手機號,就必定會報錯,那麼說明你自定義的轉換器就生效了

這裏你也能夠從新建立一個視圖好比匹配郵箱,調用你的自定義轉換器類,而且傳入正則規則,也是可使用的,固然自定義的轉換器還有兩個方法也是值得一提的:

1.to_python(self, value):當請求的url中包含的參數經過正則驗證以後,會經過to_python這個方法返回給對應的視圖

舉個栗子:需求隱藏手機號的後四位替換成xxxx

from flask import Flask
from werkzeug.routing import BaseConverter
app = Flask(__name__)


class RegexConverter(BaseConverter):
    """自定義轉換器類"""
    def __init__(self, url_map, regex):
        # 調用父類的初始化方法 這裏咱們須要的第二個參數就是傳給父類
        super(RegexConverter, self).__init__(url_map)
        # 將正則表達式的參數保存到對象的屬性中,flask會去使用這個屬性來進行路由的正則匹配
        print('init 執行了')
        self.regex = regex 
        # 定義一個實例屬性存儲原手機號和加密後的手機號
        self.phone = []

    def to_python(self, value):
        print('to_python 執行了')
        # 將原有的手機號碼存入集合中
        self.phone.append(value) 
        # 自制加密
        self.value = value[0:8] + "XXXX"
        # 將加密的數據存入集合中
        self.phone.append(self.value)
        return self.phone

# 將自定義的轉換器添加到flask的應用中
app.url_map.converters['re'] = RegexConverter

# 這裏模擬匹配手機號碼
# 127.0.0.1:5000/send/138XXXXXXXX
@app.route("/send/<re(r'1[34578]\d{9}'):phone_num>")
def send_sms(phone_num):
    original_number = phone_num[0]
    encrypted_data = phone_num[1]
    return "%s send message to %s" % (original_number, encrypted_data)

if __name__ == '__main__':
    # 查看路由信息
    print(app.url_map)
    # 啓動flask程序
    app.run(debug=True)
    

返回結果:

若是傳入的參數沒法匹配正則就不會去執行to_python,若是沒有重寫to_python方法,默認會調用父類的to_python方法,而後將返回值給調用的視圖函數:ps:在文檔中爲了避免顯得冗長,我刪除了一個沒用的視圖,可是執行時候還在那因此這裏會有兩個視圖

2.to_url(self, value):當使用到url_for的時候使用到

大體流程:定義了一個index函數用於跳轉到send_sms中,這裏index視圖函數使用url_for 因此會調用to_url方法,首先訪問127.0.0.1:5000/ 會跳轉到send_sms

from flask import Flask, current_app, redirect, url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)


class RegexConverter(BaseConverter):
    """自定義轉換器類"""
    def __init__(self, url_map, regex):
        # 調用父類的初始化方法 這裏咱們須要的第二個參數就是傳給父類
        super(RegexConverter, self).__init__(url_map)
        # 將正則表達式的參數保存到對象的屬性中,flask會去使用這個屬性來進行路由的正則匹配
        print('init 執行了')
        self.regex = regex 
        self.phone = []

    def to_python(self, value):
        print('to_python 執行了')
        self.phone.append(value) 
        self.value = value[0:8] + "XXXX"
        self.phone.append(self.value)
        return self.phone

    def to_url(self, value):
        print('to_url 執行了')
        return value

# 將自定義的轉換器添加到flask的應用中
app.url_map.converters['re'] = RegexConverter

# 這裏模擬匹配手機號碼
# 127.0.0.1:5000/send/138XXXXXXXX
@app.route("/send/<re(r'1[34578]\d{9}'):phone_num>")
def send_sms(phone_num):
    print('send_sms 視圖函數執行')
    original_number = phone_num[0]
    encrypted_data = phone_num[1]
    return "%s send message to %s" % (original_number, encrypted_data)


@app.route('/')
def index():
    # 使用反向解析到咱們定義的send_sms視圖函數
    # 由於路徑匹配規則中有phone_num 因此這裏咱們須要傳參
    print('index')
    url = url_for('send_sms', phone_num='18000000000')
    return redirect(url)


if __name__ == '__main__':
    # 查看路由信息
    print(app.url_map)
    # 啓動flask程序
    app.run(debug=True)

返回結果:訪問127.0.0.1:5000/

後臺查看一下執行流程:

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息