flask開發

flask入門(URL)

flask簡介:

flask是一款非常流行的Python Web框架,出生於2010年,作者是Armin Ronacher,本來這個項目只是作者在愚人節的一個玩笑,後來由於非常受歡迎,進而成為一個正式的項目。目前為止最新的版本是0.11.1。python學習交流 125980254 群內每天更新學習視頻!

flask自2010年發布第一個版本以來,大受歡迎,深得開發者的喜愛,並且在多個公司已經得到了應用,flask能如此流行的原因,可以分為以下幾點:

微框架、簡潔、只做他需要做的,給開發展提供了很大的擴展性。

Flask和相關的依賴(Jinja2、Werkzeug)設計得非常優秀,用起來很爽。

Advertisements

開發效率非常高,比如使用SQLAlchemy的ORM操作資料庫可以節省開發者大量書寫sql的時間。

社會活躍度非常高。

Flask的靈活度非常之高,他不會幫你做太多的決策,即使做已經幫你做出選擇,你也能非常容易的更換成你需要的,比如:

使用Flask開發資料庫的時候,具體是使用SQLAlchemy還是MongoEngine或者是不用ORM而直接基於MySQL-Python這樣的底層驅動進行開發都是可以的,選擇權完全掌握在你自己的手中。區別於Django,Django內置了非常完善和豐富的功能,並且如果你想替換成你自己想要的,要麼不支持,要麼非常麻煩。

把默認的Jinija2模板引擎替換成Mako引擎或者是其他模板引擎都是非常容易的。

Advertisements

第一個flask程序:

用pycharm新建一個flask項目,新建項目的截圖如下: 點擊create后創建一個新項目,然後在helloworld.py文件中書寫代碼:

#coding: utf8

# 從flask框架中導入Flask類

from flask import Flask

# 傳入__name__初始化一個Flask實例

app = Flask(__name__)

# app.route裝飾器映射URL和執行的函數。這個設置將根URL映射到了hello_world函數上

@app.route('/')

def hello_world():

return 'Hello World!'

if __name__ == '__main__':

# 運行本項目,host=0.0.0.0可以讓其他電腦也能訪問到該網站,port指定訪問的埠。默認的host是127.0.0.1,port為5000

app.run(host='0.0.0.0',port=9000)

然後點擊運行,在瀏覽器中輸入http://127.0.0.1:9000就能看到hello world了。需要說明一點的是,app.run這種方式只適合於開發,如果在生產環境中,應該使用Gunicorn或者uWSGI來啟動。如果是在終端運行的,可以按ctrl+c來讓服務停止。

設置為DEBUG模式:

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

開啟DEBUG模式有三種方式:

直接在應用對象上設置:

app.debug = True

app.run()

在執行run方法的時候,傳遞參數進去:

app.run(debug=True)

在config屬性中設置:

app.config.update(DEBUG=True)

如果一切正常,會在終端列印以下信息:

* Restarting with stat

* Debugger is active!

* Debugger pin code: 294-745-044

* Running on http://0.0.0.0:9000/ (Press CTRL+C to quit)

需要注意的是,只能在開發環境下開啟DEBUG模式,因為DEBUG模式會帶來非常大的安全隱患。

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

項目配置:

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

直接硬編碼:

app = Flask(__name__)

app.config['DEBUG'] = True

因為app.config是flask.config.Config的實例,而Config類是繼承自dict,因此可以通過update方法:

app.config.update(

DEBUG=True,

SECRET_KEY='...'

)

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

# 1. 通過模塊字元串

app.config.from_object('settings')

# 2. 通過模塊對象

import settings

app.config.from_object(settings)

也可以通過另外一個方法載入,該方法就是app.config.from_pyfile(),該方法傳入一個文件名,通常是以.py結尾的文件,但也不限於只使用.py後綴的文件:

app.config.from_pyfile('settings.py',silent=True)

# silent=True表示如果配置文件不存在的時候不拋出異常,默認是為False,會拋出異常。

Flask項目內置了許多的配置項,所有的內置配置項,可以在這裡查看。

URL與函數的映射:

從之前的helloworld.py文件中,我們已經看到,一個URL要與執行函數進行映射,使用的是@app.route裝飾器。@app.route裝飾器中,可以指定URL的規則來進行更加詳細的映射,比如現在要映射一個文章詳情的URL,文章詳情的URL是/article/id/,id有可能為1、2、3...,那麼可以通過以下方式: python @app.route('/article/<id>/') def article(id): return '%s article detail' % id 其中<id>,尖括弧是固定寫法,語法為<variable_name>,variable_name默認的數據類型是字元串。如果需要指定類型,則要寫成<converter:variable_name>,其中converter就是類型名稱,可以有以下幾種:

string: 默認的數據類型,接受沒有任何斜杠「/」的文本。

int: 接受整形。

float: 接受浮點類型。

path: 和string的類似,但是接受斜杠。

uuid: 只接受uuid字元串。

any:可以指定多種路徑,這個通過一個例子來進行說明:

@app.route('/<any(article,blog):url_path>/')

def item(url_path):

return url_path

以上例子中,item這個函數可以接受兩個URL,一個是/article/,另一個是/blog/。並且,一定要傳url_path參數,當然這個url_path的名稱可以隨便。

如果不想定製子路徑來傳遞參數,也可以通過傳統的?=的形式來傳遞參數,例如:/article?id=xxx,這種情況下,可以通過request.args.get('id')來獲取id的值。如果是post方法,則可以通過request.form.get('id')來進行獲取。

構造URL(url_for):

一般我們通過一個URL就可以執行到某一個函數。如果反過來,我們知道一個函數,怎麼去獲得這個URL呢?url_for函數就可以幫我們實現這個功能。url_for()函數接收兩個及以上的參數,他接收函數名作為第一個參數,接收對應URL規則的命名參數,如果還出現其他的參數,則會添加到URL的後面作為查詢參數。

通過構建URL的方式而選擇直接在代碼中拼URL的原因有兩點:

將來如果修改了URL,但沒有修改該URL對應的函數名,就不用到處去替換URL了。

url_for()函數會轉義特殊字元和Unocode數據,這些工作都不需要我們自己處理。

下面用一個例子來進行解釋: ```python from flask import Flask,url_for app = Flask(name)

@app.route('/article/<id>/')

def article(id):

return '%s article detail' % id

# 這行的代碼可以在交互模式下產生請求上下文,不用`app.run()`來運行這個項目,直接可以運行下面的代碼,

# 也會有`flask`上下文

with app.test_request_context():

print url_for('article',id='1')

print url_for('article',id='2',next='/')

```

執行后的結果如下:

> /article/1/

> /article/2/?next=%2F

自定義URL轉換器:

剛剛在URL映射的時候,我們看到了Flask內置了幾種數據類型的轉換器,比如有int/string等。如果Flask內置的轉換器不能滿足你的需求,此時你可以自定義轉換器。自定義轉換器,需要滿足以下幾個條件:

轉換器是一個類,且必須繼承自werkzeug.routing.BaseConverter。

在轉換器類中,必須實現to_python(self,value)方法,這個方法的返回值,將會傳遞到view函數中作為參數。

在轉換器類中,必須實現to_url(self,values)方法,這個方法的返回值,將會在調用url_for函數的時候生成符合要求的URL形式。

比如,拿一個官方的例子來說,Reddit可以通過在URL中用一個加號(+)隔開社區的名字,方便同時查看來自多個社區的帖子。比如訪問「www.reddit.com/r/flask+lisp/」的時候,就同時可以查看flask和lisp兩個社區的帖子,現在我們自定義一個轉換器來實現這個功能:

#coding: utf8

from flask import Flask,url_for

from werkzeug.routing import BaseConverter

class ListConverter(BaseConverter):

def __init__(self,url_map,separator='+'):

super(ListConverter,self).__init__(url_map)

self.separator = separator

def to_python(self, value):

return value.split(self.separator)

def to_url(self, values):

return self.separator.join(BaseConverter.to_url(self,value) for value in values)

@app.route('/community1/<list:page_names>')

def community1(page_names):

return '%s+%s' % tuple(page_names)

@app.route('/community2/<list('|'):page_names>/')

def community2(page_names):

return "%s|%s" % tuple(page_names)

communityu1使用的是默認的+號進行連接,而第二種方式使用了|進行連接。

URL唯一:

Flask的URL規則是基於Werkzeug的路由模塊。這個模塊的思想是基於Apache以及更早的HTTP伺服器的主張,希望保證優雅且唯一的URL。

舉個例子:

@app.route('/projects/')

def projects():

return 'project page'

上述例子中,當訪問一個結尾不帶斜線的URL會被重定向到帶斜線的URL上去。這樣有助於避免搜索引擎搜索同一個頁面兩次。

再看一個例子:

@app.route('/about')

def about():

return 'about page'

以上例子中,當訪問帶斜線的URL(/about/)會產生一個404("Not Found")錯誤。

指定HTTP方法:

在@app.route()中可以傳入一個關鍵字參數methods來指定本方法支持的HTTP方法,默認只響應GET請求,看以下例子: python @app.route('/login/',methods=['GET','POST']) def login(): return 'login' 以上裝飾器將讓login的URL既能支持GET又能支持POST。

頁面跳轉和重定向:

重定向分為永久性重定向和暫時性重定向,在頁面上體現的操作就是瀏覽器會從一個頁面自動跳轉到另外一個頁面。比如用戶訪問了一個需要許可權的頁面,但是該用戶當前並沒有登錄,因此我們應該給他重定向到登錄頁面。

永久性重定向:

http的狀態碼是301,多用於舊網址被廢棄了要轉到一個新的網址確保用戶的訪問,最經典的就是京東網站,你輸入www.jingdong.com的時候,會被重定向到www.jd.com,因為jingdong.com這個網址已經被廢棄了,被改成jd.com,所以這種情況下應該用永久重定向。

暫時性重定向:

http的狀態碼是302,表示頁面的暫時性跳轉。比如訪問一個需要許可權的網址,如果當前用戶沒有登錄,應該重定向到登錄頁面,這種情況下,應該用暫時性重定向。

在flask中,重定向是通過flask.redirect(location,code=302)這個函數來實現的,location表示需要重定向到的URL,應該配合之前講的url_for()函數來使用,code表示採用哪個重定向,默認是302也即暫時性重定向,可以修改成301來實現永久性重定向。

以下來看一個例子,關於在flask中怎麼使用重定向:

from flask import Flask,url_for,redirect

app = Flask(__name__)

app.debug = True

@app.route('/login/',methods=['GET','POST'])

def login():

return 'login page'

@app.route('/profile/',methods=['GET','POST'])

def profile():

name = request.args.get('name')

if not name:

# 如果沒有name,說明沒有登錄,重定向到登錄頁面

return redirect()

else:

return name

關於響應(Response):

視圖函數的返回值會被自動轉換為一個響應對象,Flask的轉換邏輯如下:

如果返回的是一個合法的響應對象,則直接返回。

如果返回的是一個字元串,那麼Flask會重新創建一個werkzeug.wrappers.Response對象,Response將該字元串作為主體,狀態碼為200,MIME類型為text/html,然後返回該Response對象。

如果返回的是一個元組,元祖中的數據類型是(response,status,headers),只能包含一個元素。status值會覆蓋默認的200狀態碼,headers可以是一個列表或者字典,作為額外的消息頭。

如果以上條件都不滿足,Flask會假設返回值是一個合法的WSGIt應用程序,並通過Response.force_type(rv,request.environ)轉換為一個請求對象。

以下將用例子來進行說明:

第一個例子:直接使用Response創建:

from werkzeug.wrappers import Response

@app.route('/about/')

def about():

resp = Response(response='about page',status=200,content_type='text/html;charset=utf-8')

return resp

第二個例子:可以使用make_response函數來創建Response對象,這個更加的方便,因為他封裝了默認的Content-Type以及status等:

from flask import make_response

@app.route('/about/')

def about():

return make_response('about page')

第三個例子:通過返回元組的形式:

@app.errorhandler(404)

def not_found():

return 'not found',404

第四個例子:自定義響應。自定義響應必須滿足三個條件:

必須繼承自Response類。

必須實現類方法force_type(cls,rv,environ=None)。

必須指定app.response_class為你自定義的Response

以下將用一個例子來進行講解,Restful API都是通過JSON的形式進行傳遞,如果你的後台跟前台進行交互,所有的URL都是發送JSON數據,那麼此時你可以自定義一個叫做JSONResponse的類來代替Flask自帶的Response類:

from flask import Flask,jsonify

from werkzeug.wrappers import Response

app = Flask(__name__)

class JSONResponse(Response):

default_mimetype = 'application/json'

@classmethod

def force_type(cls,response,environ=None):

if isinstance(response,dict):

response = jsonify(response)

return super(JSONResponse,cls).force_type(response,environ)

app.response_class = JSONResponse

@app.route('/about/')

def about():

return {"message":"about page"}

if __name__ == '__main__':

app.run(host='0.0.0.0',port=8000)

此時如果你訪問/about/這個URL,那麼在頁面中將會顯示:

{

"message": "about page"

}

注意以上例子,如果不寫app.response_class = JSONResponse,將不能正確的將字典返回給客戶端。python學習交流 125980254 群內有大量的學習視頻!因為字典不在Flask的響應類型支持範圍中,那麼將調用app.response_class這個屬性的force_type類方法,而app.response_class的默認值為Response,因此會調用Response.force_class()這個類方法,他有一個默認的演算法轉換成字元串,但是這個演算法不能滿足我們的需求。因此,我們要設置app.response_class=JSONResponse,然後重寫JSONResponse中的force_type類方法,在這個方法中將字典轉換成JSON格式的字元串后再返回。

Advertisements

你可能會喜歡