Python全棧(七)Flask框架之1.Flask簡介與URL和視圖介紹


Flask簡介與URL和視圖介紹

一、虛擬環境介紹

1.虛擬環境與全局環境

有時候安裝了一個Python庫,可能在IDE如PyCharm中不能使用,這是因為:
通過pip安裝的庫默認一般在全局環境中,而PyCharm一般會默認創建虛擬環境,所以兩者的環境不一致,導致安裝的包不能正常導入使用,解決辦法有2種:

  • 在PyCharm虛擬環境中安裝庫,使庫位於虛擬環境中
  • 將PyCharm的環境設置為全局環境,即我們通常使用的Python,設置為Python的安裝目錄即可
    設置示意如下:
    PyCharm 設置編譯環境

2.為什么需要虛擬環境

一般情況下,Python第三方庫安裝是直接通過pip install xxx的方式進行安裝的,這樣安裝會將庫安裝到系統級的Python環境中。
但是有時可能會面臨這樣的問題:如果現在用Django 1.10.x寫了個網站,但是同時有一個Django 0.9開發的項目需要維護,並i企鵝可能Django 1.10不再兼容Django 0.9的一些語法了,這就需要同時擁有Django 1.10和Django 0.9兩套環境,這時候我們就可以通過虛擬環境來解決這個問題。

3.虛擬環境的安裝和簡單操作

虛擬環境管理有很多工具,這里我選擇pipenv。

pipenv的安裝

命令:

  • Windows下
pip install pipenv
  • Mac下
brew install pipenv
  • Linux下
pip install pipenv

創建虛擬環境

安裝之后即可創建虛擬環境。
創建虛擬環境使用命令pipenv shell,如下:
pipenv shell

出現圖中所標提示Flask_Framework-rL0Lvhvz及說明安裝成功,此時再運行pip list可以看到虛擬環境中默認安裝的庫:

Package    Version
---------- -------
pip        20.0.2
setuptools 46.1.3
wheel      0.34.2

不能同時使用全局環境和虛擬環境的庫,只能選擇使用其中一個。
虛擬環境默認會安裝到系統盤(C盤)下的當前用戶目錄下的 .virtualenvs 目錄下,如果想指定安裝到其他目錄,可以設置系統環境變量,示意如下:
pipenv 設置安裝環境變量
此時再安裝虛擬環境,即會安裝到指定的目錄下。

虛擬環境安裝好之后,需要在PyCharm中設置虛擬環境為當前創建的虛擬環境,即定位選擇虛擬環境下的python.exe文件,與前面方法相同。

需要在虛擬環境中通過命令pip install flask安裝Flask,再查看安裝的庫,結果如下:

Package      Version
------------ -------
click        7.1.1
Flask        1.1.2
itsdangerous 1.1.0
Jinja2       2.11.1
MarkupSafe   1.1.1
pip          20.0.2
setuptools   46.1.3
Werkzeug     1.0.1
wheel        0.34.2

顯然,在安裝flask時,安裝了存在依賴關系的其他庫。
如果電腦中同時擁有Python3和Python2,可以指定版本:

pipenv --three  # 泛指Python3的版本 
pipenv --two    # 泛指Python2的版本 
pipenv --python 3.7 # 指定Python具體版本

虛擬環境管理

pipenv shell    # 如果虛擬環境已存在則進入虛擬環境,否則創建並進入虛擬環境
exit            # 退出虛擬環境
pipenv --rm     # 刪除整個環境 不會刪除pipfile

pipfile和pipfile.lock

在創建虛擬環境后,虛擬環境目錄下會生成pipfile文件,內容如下:

[[source]]
name = “pypi”
url = “https://pypi.org/simple”
verify_ssl = true

[dev-packages]

[packages]

[requires] python_version = “3.7”

參數說明:

  • url
    可以指定國內pip源,否則下載庫可能會很慢
  • dev-packages
    開發環境
  • packages
    生產環境
  • django = “*”
    *表示最新版本
  • requires
    Python版本

pipfile.lock詳細記錄環境依賴,並且使用了Hash算法以保證完整的對應關系。

如果需要將安裝的庫記錄到Pipfile中,可以使用pip install --dev 庫名將庫安裝到開發環境。

在虛擬環境中運行項目示意run參數:

pipenv run python manage.py runserver

pipenv有一個缺點:
lock不穩定而且時間非常長,所以安裝包的時候記得加上--skip-lock,如下:

pipenv install django --skip-lock

最后開發完成要提交到倉庫的時候再執行pipenv lock命令。

二、Flask介紹

1.Flask簡介

flask是一款非常流行的Python Web框架,誕生於2010年,作者是Armin Ronacher,這個項目最初只是作者在愚人節的一個玩笑,后來由於非常受歡迎,逐漸成為一個正式的項目。
flask自2010年發布第一個版本以來,大受歡迎,深得開發者的喜愛,並且在多個公司已經得到了應用,flask能如此流行的原因,可以分為以下幾點:

  • 微框架、簡潔,只做它需要做的,靈活度非常高,給開發者提供了很大的擴展性。
    Flask不會幫開發者做太多的決策,一切都可以按照自己的意願進行更改。
    • 使用Flask開發數據庫的時候,具體是使用SQLAlchemy還是MongoEngine,選擇權完全掌握在你自己的手中。區別於Django,Django內置了非常完善和豐富的功能,並且如果你想替換成你自己想要的,要么不支持,要么非常麻煩。
    • 把默認的Jinija2模板引擎替換成其他模板引擎都是非常容易的。
  • Flask和相應的插件寫得很好。
  • 開發效率非常高,比如使用SQLAlchemy的ORM操作數據庫可以節省開發者書寫大量sql的時間。

2.第一個Flask程序

from flask import Flask

# 傳入__name__初始化一個Flask實例
app = Flask(__name__)


# 裝飾器,將當前路由映射到指定函數
@app.route('/')
def hello_world():
    return 'hello world'


if __name__ == '__main__':
    app.run()

打印:

 * Serving Flask app "first_flask" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

此時已經創建服務,在瀏覽器中打開http://127.0.0.1:5000/即可看到:
flask first program
並且在開啟的服務狀態欄下會看到請求的記錄,如:

127.0.0.1 - - [09/Apr/2020 07:54:10] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [09/Apr/2020 07:54:10] "GET /favicon.ico HTTP/1.1" 404 -

說明:

  • @app.route('/')裝飾器映射URL和執行的函數。這個設置將URL映射到指定的函數上,例中指定當前路由為根目錄,如果為根目錄時也可以不寫 /,但是盡量寫上以示區別。
  • app.run()是讓flask項目運行起來,可以指定主機號和端口號。
    默認的host是127.0.0.1,port為5000host=0.0.0.0可以讓其他電腦也能訪問到該網站,port指定訪問的端口。

三、設置Debug模式

默認情況下flask不會開啟DEBUG模式,開啟DEBUG模式后,flask會在每次保存代碼的時候自動的重新載入代碼,並且如果代碼有錯誤,會在終端進行提示。
hello_world()函數中加入錯誤代碼進行測試:

from flask import Flask

app = Flask(__name__)


# 裝飾器,將當前路由映射到指定函數
@app.route('/')
def hello_world():
    result = 1 / 0
    return 'hello world'


if __name__ == '__main__':
    app.run()

重新運行開啟服務后,會發現:
flask server error
在日志中也會發現報錯:

[2020-04-09 08:07:17,881] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
  File "C:\Users\Lenovo\.virtualenvs\Flask_Framework-rL0Lvhvz\lib\site-packages\flask\app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\Lenovo\.virtualenvs\Flask_Framework-rL0Lvhvz\lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\Lenovo\.virtualenvs\Flask_Framework-rL0Lvhvz\lib\site-packages\flask\app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\Lenovo\.virtualenvs\Flask_Framework-rL0Lvhvz\lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "C:\Users\Lenovo\.virtualenvs\Flask_Framework-rL0Lvhvz\lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\Lenovo\.virtualenvs\Flask_Framework-rL0Lvhvz\lib\site-packages\flask\app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "xxx/first_flask.py", line 9, in hello_world
    result = 1 / 0
ZeroDivisionError: division by zero
127.0.0.1 - - [09/Apr/2020 08:07:17] "GET / HTTP/1.1" 500 -

這與顯然很麻煩,每次修改之后必須重新運行,而且錯誤信息在日志中才能看到。
我們可以開啟Debug模式,這樣每次修改代碼后都會載入代碼重新運行,並且代碼有問題時會顯示錯誤信息。

開啟Debug模式有幾種方式:

  • run()方法中設置debug參數為True
if __name__ == '__main__':
    app.run(debug=True)
  • 設置app對象實例的屬性為True
if __name__ == '__main__':
    app.debug = True
    app.run()
  • 通過配置參數config設置
if __name__ == '__main__':
    app.config.update(DEBUG=True)
    app.run()

config是繼承自字典類型的,所以可以使用字典的update()方法。

開啟Debug模式測試如下:

from flask import Flask

app = Flask(__name__)


# 裝飾器,將當前路由映射到指定函數
@app.route('/')
def hello_world():
    result = 1 / 0
    return 'hello world'


if __name__ == '__main__':
    app.run(debug=True)

此時再看網頁:
flask error debug
並且控制台中也會提示已開啟Debug模式:

 * Serving Flask app "first_flask" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 313-629-160
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

在開啟了DEBUG模式后,當程序有異常而進入錯誤堆棧模式,第一次點擊某個堆棧想查看變量值的時候,頁面會彈出一個對話框,提示輸入PIN值,比如在剛剛啟動的項目中的PIN值為313-629-160,輸入這個值后,Werkzeug會把這個PIN值作為cookie的一部分保存起來,並在8小時后過期,8小時內不需要再輸入PIN值。這樣做的目的是為了提高安全性,讓調試模式下的攻擊者更難攻擊到本站。

現在每次修改完代碼保存之后,都會自動加載代碼重啟服務,不需要再手動關閉服務再重啟了。

此時在報錯的網頁中可以Debug,需要使用控制台提供的PIN,操作示意如下:
flask webpage debug
Debug模式是在開發環境中開啟的,開發完成上線之后要關閉Debug模式,因為DEBUG模式會帶來非常大的安全隱患。

四、配置與配置文件

Flask項目的配置,都是通過app.config對象來進行配置的。
比如要配置一個項目處於DEBUG模式下,那么可以使用app.config['DEBUG] = True來進行設置,那么Flask項目將以DEBUG模式運行。
在Flask項目中,有四種方式進行項目的配置。

1.直接硬編碼

app = Flask(__name__)
app.config['DEBUG'] = True

硬編碼的方式不靈活,不便於進行復用。

2.通過update()方法

因為app.config是flask.config.Config的實例,而Config類是繼承自dict,因此可以通過update()方法進行配置。

app.config.update(
   DEBUG=True,
   SECRET_KEY='...'
)

3.通過from_object()方法

如果配置項特別多,可以把所有的配置項都放在一個模塊中,然后通過加載模塊的方式進行配置,假設有一個settings.py模塊,專門用來存儲配置項的,此你可以通過app.config.from_object()方法進行加載,並且該方法既可以接收模塊的的字符串名稱,也可以模塊對象。
有兩種形式:

# 1. 通過模塊字符串
app.config.from_object('settings')
# 2. 通過模塊對象
import settings
app.config.from_object(settings)

添加配置文件后,將配置項都放入該文件中,其他文件直接引用該配置文件中的配置項,提高了代碼的復用性、降低了耦合度,同時,在配置文件中修改了配置項時,其他代碼中均不需要修改,從而提高了代碼的靈活性。
新建config.py文件,添加一些配置項如下:

# 設置Debug模式為True
DEBUG = True

# 指定HOST
HOST = '127.0.0.1'

在flask文件中導入:

from flask import Flask
import config

app = Flask(__name__)


# 裝飾器,將當前路由映射到指定函數
@app.route('/')
def hello_world():
    result = 1 / 0
    return 'hello world'


if __name__ == '__main__':
    app.config.from_object(config)
    app.run()

再運行,也能開啟Debug模式。
也可以通過字符串形式導入:

if __name__ == '__main__':
    app.config.from_object('config')
    app.run()

此時不需要再導入config模塊。

4.通過from_pyfile()方法

app.config.from_pyfile()方法傳入一個文件名,通常是以.py結尾的文件,但也不限於只使用.py后綴的文件。
通過導入Python文件的形式導入配置文件:

if __name__ == '__main__':
    app.config.from_pyfile('config.py')
    app.run()

from_pyfile()方法有一個silent參數,設置為True時,如果配置文件不存在也不會報錯;
不僅支持Python格式的配置文件,也支持.ini等格式。

五、URL與函數的映射

從前面的例子中,我們可以看到,一個URL要與執行函數進行映射,使用的是@app.route裝飾器。
@app.route裝飾器中,可以指定URL的規則來進行更加詳細的映射,比如現在要映射一個文章詳情的URL,文章詳情的URL是/article/id/,id有可能為1、2、3…,那么可以通過以下方式:

@app.route('/article/<id>')
def article(id):
   return '%s article detail' % id

其中,尖括號是固定語法,表示地址中傳入的參數,默認的數據類型是字符串。
如果需要限制參數類型,則要寫成converter:variable,其中converter是類型名稱,可以有以下幾種:

  • string
    默認的數據類型,接受任何沒有斜杠/的字符串。
  • int
    整型。
  • float
    浮點型。
  • path
    和string類似,但是可以傳遞斜杠/。
  • uuid
    uuid類型的字符串。
  • any
    可以同時指定多種路徑。

新增路由域函數映射測試:

from flask import Flask


app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'hello world'


@app.route('/corley')
def hello_corley():
    return '這是我的第一個Flask頁面'

if __name__ == '__main__':
    app.run(debug=True)

顯示:
flask url view map
顯然,在地址中訪問http://127.0.0.1/corley可以訪問到,因為在flask中已經定義了。
同時還可以動態傳入參數:

from flask import Flask


app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'hello world'


@app.route('/corley')
def hello_corley():
    return '這是我的第一個Flask頁面'

@app.route('/list/<aid>')
def article_list(aid):
    return '這是第{}篇文章'.format(aid)

if __name__ == '__main__':
    app.run(debug=True)

顯示:
flask url view map params
顯然,因為未定義 /list 所以不能訪問http://127.0.0.1:5000/list
可以根據傳入的參數動態顯示視圖,但是並未對數據類型進行限制,可以增加對數據類型的限制:

from flask import Flask


app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'hello world'


@app.route('/corley')
def hello_corley():
    return '這是我的第一個Flask頁面'

@app.route('/list/<int:aid>')
def article_list(aid):
    return '這是第{}篇文章'.format(aid)

if __name__ == '__main__':
    app.run(debug=True)

顯示:
flask url view map params int
顯然,此時參數只能是整型數字了。
一般情況下參數中不能含有 /,要想含有 /,必須限制為path類型,除了此區別,path與string類型基本一樣。
示例如下:

from flask import Flask


app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'hello world'


@app.route('/corley')
def hello_corley():
    return '這是我的第一個Flask頁面'

@app.route('/list/<int:aid>')
def article_list(aid):
    return '這是第{}篇文章'.format(aid)

@app.route('/list/<path:aid>')
def comment_list(aid):
    return '這是第{}個評論'.format(aid)

if __name__ == '__main__':
    app.run(debug=True)

顯示:
flask url view map params path
顯然,如果參數為數字時,匹配article_list(aid)函數,如果為字符串類型或者參數中含有 / 時匹配comment_list(aid)函數。

訪問兩個路徑用同一個函數可以用any來限制,示例如下:

from flask import Flask


app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'hello world'


@app.route('/corley')
def hello_corley():
    return '這是我的第一個Flask頁面'

@app.route('/list/<int:aid>')
def article_list(aid):
    return '這是第{}篇文章'.format(aid)

@app.route('/list/<path:aid>')
def comment_list(aid):
    return '這是第{}個評論'.format(aid)

@app.route('/<any(notice,follow):url_path>/')
def message(url_path):
    return '當前路徑是'.format(url_path)

if __name__ == '__main__':
    app.run(debug=True)

顯示:
flask url view map params any
此時需要在路由路徑最后添加 / 才能正常訪問。
如果不想指定子路徑來傳遞參數,也可以通過 ?= 的形式來傳遞參數,例如:/article?id=xxx,這種情況下,可以通過request.args.get('id')來獲取id的值。如果是post方法,則可以通過request.form.get('id')來進行獲取。
在flask中添加這類的地址參數需要先從flask中導入request,示例如下:

from flask import Flask
from flask import request


app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'hello world'


@app.route('/corley')
def hello_corley():
    return '這是我的第一個Flask頁面'

@app.route('/list/<int:aid>')
def article_list(aid):
    return '這是第{}篇文章'.format(aid)

@app.route('/list/<path:aid>')
def comment_list(aid):
    return '這是第{}個評論'.format(aid)

@app.route('/<any(notice,follow):url_path>/')
def message(url_path):
    return url_path

@app.route('/wd')
def baidu_search():
    return request.args.get('keyword')

if __name__ == '__main__':
    app.run(debug=True)

顯示:
flask url view map params wd
顯然,如果傳入的參數未在函數中定義,會報錯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM