# Flask實作_ext_12_Flast-BluePrint_藍圖 ###### tags: `flask` `flask_ext` `python` `blueprint` ## 說明 `blueprint`主要用來整合我們的專案路由,不過依著你使用的專案架構是採用功能面的或是模組面,`blueprint`的意思可能有那麼一點點的不同。 不管如何,隨著我們的專案愈見增長,`blueprint`確實可以讓我們更有效的設置我們的路由與其靜態資源,使用上很單純的就是『定義、關聯、使用、註冊』,that's all。 唯一在官方文件上特別說明的,就是建議在註冊`blueprint`的時候定義`url_prefix`<sub>(路由前綴)</sub>。剩下的我們透過案例來直接觀察,並且了解`blueprint`究竟幫我們處理些什麼。 ## 表達式 ``` 物件命名 = Blueprint(blueprint_name,\_\_name\_\_) url_prefix:url的前綴 ``` ## 範例_不採用`blueprint` :::info 除非程式碼需要特別說明,不然這個部份不會詳列程式碼 ::: 假設我們有一個網頁專案,並且我們希望路由可以依不同功能設置對應的url,最快的方法當然就是在`app.route`上直接設置。 測試架構很簡單,如下圖所示: ![](https://i.imgur.com/NJcXb0Y.png) 架構上設置了兩個功能,`afunc`與`bfunc`,並且在執行專案之前透過`app.url_map`來觀察路由,如下圖: ![](https://i.imgur.com/Yr6MPMF.png) 如果我們希望在路由有所區隔怎麼辦?那就手動在專案前面加上一個前綴就好了,以後只要在`afunc`這個功能的,我們就加一個`afunc`在前面就可以了,不錯,那可以下課了,如下設置: ![](https://i.imgur.com/2pjiDnn.png) 當有一天你累了,沒有喝保力達蠻牛了,就會手誤: ![](https://i.imgur.com/uUC9YBX.png) ![](https://i.imgur.com/EYeKQ6U.png) 又或者,你連路由都重覆了還不自知,那就是先註冊的先贏了: ![](https://i.imgur.com/1thKN3z.png) ![](https://i.imgur.com/QxVZxrm.png) 如果用`endpoint`去執行`url_for`的話,`afunc`與`bfunc`都會指向同一個路由,因為`afunc`先註冊到`url_map`,所以`pop`的時候會丟出先註冊的那一個<sub>(在沒有另外設置`endpoint`的情況下,也可以試著將`from app.bfunc import view`改置於前測試)</sub>。 路由太多的情況下,開發人員確實很有機會因為手誤而造成很難察覺的失誤。 ## 範例_使用`blueprint` 我們調整上面的範例改透過`blueprint`來處理,依著四個流程:定義、關聯、使用、註冊,下面利用兩張圖來說明,設置說明皆書寫於兩張圖中間。 ![](https://i.imgur.com/DyASuZP.png) * 上面左圖:`afunc.__init__py` 1. 在初始化`package`的時候定義`blueprint`, 2. 設置`blueprint`與`package`內的`view.py`做關聯 * 這一步很重要,因為我們會在`view`中導入`blueprint`,如果沒有這麼做,會造成異常。 * 我們採用了官方文件的建議,不在定義的時候設置前綴,而是在註冊的時候定義前綴。 * 下面右圖: 1. 在`afunc`的`view`中`import`在初始化中設置的`blueprint`,並且取代掉原本的`app.route`,改`blueprint.route`<sub>(`blueprint.route`)請依你設置的命名名稱變化,此例為`blue_afunc.route`</sub>。 * 下面左圖: 1. 實作Flask之後註冊`blueprint`,在這邊依官方建議設置前綴,所以只要是經過`afunc`這個`blueprint`的路由,都必需加上`/afunc`。 * 上面右圖: 1. 雖然`afunc`與`bfunc`中都有一個`bfunc`的function name,但是透過`blueprint`,這已經不會造成異常了。 ![](https://i.imgur.com/CjC1yIh.png) 觀察`url_map`可以看的到,多了一個前綴`/afunc`,如下圖: ![](https://i.imgur.com/GEFLJ8r.png) 接著我們將`bfunc`也依樣設置`blueprint`,一樣觀察`url_map`的變化,如下圖設置說明: ![](https://i.imgur.com/8iWtPWB.png) 左圖:追加註冊`bfunc`的`blueprint`,並加入前綴`/bfunc` 中圖:定義與關聯`blueprint` 右圖:調整`app.route`為`blue_bfunc.route` 再次的觀察`url_map`,兩個相同名稱的View Function(afunc)已經確實的被區隔了,一個是`afunc/afunc/afunc`,一個是`bfunc/afunc/afunc`,並且注意到後面的`endpoint`對應,也都有了`blueprint_name`。 這很重要,因為加入`blueprint`之後,你的`url_for`都必需加上`blueprint_name`才可以。 ![](https://i.imgur.com/Z4schF7.png) 最後,一定會很亂,所以,不要亂,看下圖的說明: ![](https://i.imgur.com/v9WF7Fr.png) ## 總結 要特別注意不斷提到的部份,`url_for`在導入`blueprint`之後,務必加入`blueprint_name`才能正確的導向,如下圖: ![](https://i.imgur.com/t7g7TbN.png) 我在View Function內加入一個正確(`urlfunc_right`)跟一個錯誤(`urlfunc_error`)的路由<sub>(一個加入`blueprint_name`,一個沒有)</sub> 執行錯誤的路由之後得到錯誤訊息如下: ![](https://i.imgur.com/LA9fjCw.png) 正確的路由執行之後得到正確訊息如下: ![](https://i.imgur.com/aBJcXRM.png) 最後,在將專案改為工廠模式之後,也因為整個`url_map`的產生時機點不同了,必需使用`blueprint`才可以。