零基礎學python之構建web應用(入門級)


構建一個web應用

前面的學習回顧:

  1. IDLE是Python內置的IDE,用來試驗和執行Python代碼,可以是單語句代碼段,也可以是文本編輯器中的多語句程序。
  2. 四個內置數據結構:列表、字典、集合和元組。
  3. 已經使用過的Python語句:if , elif , else , return , for , from , import 。
  4. 已經知道Python提供的豐富的標准庫,已經使用過的模塊:datetime , random , sys , os , time , html , pprint , setuptools , pip 。
  5. Python的內置函數,稱為BIF。已經用過的BIF:print , dir , help , range , list , len , input , sorted , dict , set , tuple , type 。
  6. 已經見過的操作符:in , not in , + , - , = , == , += , * 。
  7. 處理一個序列時,[ ] 除了可以擴展元素還可以支持切片,即指定開始,步長,結束
  8. 用def 創建一個自己的函數。
  9. 利用pip 模塊把函數分組為模塊,模塊構成了代碼重用的基礎。
  10. Python中一切都是對象

接下來我們要做的是利用之前的search_for_letters函數,讓人們可以在web瀏覽器上訪問這個函數提供的服務。關於這個函數的內容在前面的隨筆有介紹。

def search_for_letters(phrase: str, letters: str) -> set:   '''FUNC:return a set of 'letters' found in 'phrase' . '''
  return set(letters).intersection(set(phrase))

先來探索一下web是怎么工作的

無論在web上做什么,都與請求和響應有關。Web請求作為用戶交互的結果從一個web瀏覽器發送到一個web服務器。在web服務器上,會形成一個web響應(或應答),並返回給web瀏覽器。整個過程可以總結為五步:

  1. 你的用戶輸入一個web地址,或者單擊一個超鏈接,或者在他的web瀏覽器中單擊一個按鈕。
  2. Web瀏覽器將用戶的動作轉換為一個web請求,通過互聯網將它發送到一個服務器。
  3. Web服務器接收到這個請求,必須決定接下來做什么……

這時候有;兩種可能性。

如果web請求只是請求一個靜態的內容,如一個HTML文件、圖像或存儲在web服務器硬盤上的其他資源,web服務器會找到這個資源,准備把它作為一個web響應返回給web瀏覽器。

如果請求的是動態內容,也就是說必須生成的內容,如果搜索結果是一個在線購物車的當前內容,web服務器會運行一些代碼來生成web響應。

  1. web服務器通過互聯網將響應發回給正在等待的web瀏覽器。
  2. Web瀏覽器接收到web響應,把它顯示在用戶的屏幕上。

我們想讓web實現的功能

讓web瀏覽器與我們的web應用交互。在瀏覽器的地址欄輸入這個微博應用的URL地址來訪問應用的服務。瀏覽器上會出現一個頁面,要求用戶提供search_for_letters函數所需要的參數。一旦輸入參數,用戶點擊一個按鈕就會看到結果。

回憶這個函數的定義,它指出這個函數需要至少一個(至多兩個)參數:phrase和letters(要在phrase中搜索letters,letters是可選的,因為它的默認值aeiou)

def search_for_letters(phrase: str, letters: str)->set:

關於這web頁面什么樣,下面是我畫出的草圖

當用戶單擊DO IT! 時,瀏覽器將這個數據發送給正在等待的web服務器,它會抽取phrase和letters的值,然后等待用戶調用search_for_letters函數。

我們需要做的事情

要構建一個能實際運行的服務器端web應用,還需要了解web應用框架,它提供了一組通用的基礎技術,可以基於這些技術構建web應用。在這里直接選擇一個名為Flask的流行框架,繼續我們的工作。

安裝Flask

Flask是一個第三方模塊,與標准庫模塊不同,需要先安裝才能導入和使用。

Python社區維護了一個集中管理第三方模塊的網站,名為PyPI(Python Package Index)

依舊是使用管理員運行cmd

python -m pip install flask

 

順便安裝了四個模塊如圖中所示,這些是flask的依賴包。

Flask提供了一組模塊可以幫助構建服務器端web應用。從理論上來講,這是一個微web框架,比較全面的web框架是Django,不過我們的需求不用這個復雜的框架,flask完全能夠勝任現在的需求。

檢查flask

創建一個新文件保存為hello_flask.py 放在一個名為webapp的文件夾中。

 

from flask import Flask app = Flask(__name__)     #注意此處是兩個下划線
 @app.route('/') def hello() -> str: return 'hello world from flask' app.run()

 

運行flask web應用

 

這是在那個文件夾里面同時按住shift和點擊右鍵,會出現在此處打開命令窗口,這樣一來可以免去切換目錄的問題。

輸入Python hello_flask.py會出現:

看到最后一行的內容表示一切正常,表示flask的服務器已經准備就緒,正在等待。現在打開一個你喜歡的瀏覽器,輸入剛才消息里面的URL地址:

http://127.0.0.1:5000/

 

 

 

瀏覽器窗口出現了剛才return后的內容,現在再來看剛才的web應用終端窗口,出現了新的狀態消息:

分析web應用的代碼

from flask import Flask

‘’’  模塊名     類名

這里也可以直接寫import flask ,然后用flask.Flask指示類,不過這個方法在這里可讀性不好。’’’

 

app = Flask(__name__)

‘’’創建一個Flask類型的對象,把它賦給app變量。

__name__是什么?

這個值由Python解釋器維護,在程序代碼中任何地方使用這個值時,它會設置為當前活動模塊的名字。

Python中把__name__叫做dunder name ‘’’

 

@app.route('/')#函數修飾符,有一個@前綴。

#函數修飾符可以調整一個已有的函數的行為,而不修改函數的代碼!

‘’’這個web應用代碼中,app變量使用Flask的route修飾符。Route允許你將一個URL web路徑與一個已有的Python函數相關聯。在這里URL ‘/’將與下一行代碼中定義的函數關聯,這個函數名為hello。當一個指向‘/’URL的請求到達服務器時,route修飾符會安排Flask web服務器調用這個函數,然后route修飾符會等待所修飾的函數生成的輸出,再將輸出返回給服務器,然后服務器再將輸出返回給正在等待的web瀏覽器。’’’

 

def hello() -> str:

return 'hello world from Flask!'

#這個函數返回一個字符串,調用時返回消息:hello world from Flask!

app.run()

#讓web應用開始運行

此時,Flask會啟動它的內置web服務器,並在這個服務器中運行你的web應用代碼。Web服務器接收到指向‘/’URL的請求時,會響應“hello world from Flask!”消息,而指向其他URL請求會得到一個404 NOT FOUND錯誤消息。

 

而終端窗口中運行的web應用也會有一個消息更新狀態:

接下來修改hello_flask.py來包含第二個URL:/search

編寫代碼使這個URL與一個名為do_search函數相關聯,它會調用search_for_letters函數(從vsearch模塊中)然后讓do_search函數返回搜素時確定的結果,在這里要用短語“life, the universe, and everything!”中搜索字符串“eriu,!”

新的代碼:

 1 from flask import Flask  2 from vsearch import search_for_letters  3 
 4 app = Flask(__name__)  5 
 6 @app.route('/')  7 def hello() -> str:  8 return 'hello world from Flask'
 9 
10 @app.route('/search') 11 def do_search() -> str: 12 return str(search_for_letters('life,the universe,and everything!','eriu,!')) 13 
14 app.run()

 

 

在命令提示符上終止剛才的終端(Ctrl+C),然后按向上的那個鍵,重新開啟一個web應用。現在處於等待狀態,然后在;瀏覽器輸入剛才定義的新的URL路徑。http://127.0.0.1:5000/search

瀏覽器出現了調用函數search_for_letters的結果:

在這里,127.0.0.1是localhost,也成為本地環回地址,而5000是協議端口號,是Flask默認的端口。

我們現在只是實現了一部分的任務,回想最開始的目的,還記得之前的草圖嗎?我們希望有一個web頁面接收輸入,另外還需要一個web頁面顯示結果。

像草圖中這樣的頁面,而不是{'e', 'i', '!', 'u', 'r', ','}。

構建HTML表單

利用模板引擎,程序員可以應用面向對象的繼承和重用概念來生成文本數據,如web頁面。

網站的外觀可以在一個頂層HTML模板中定義,這稱為基模板,然后其他HTML頁面繼承這個模板。如果對基模板進行修改,那么這個修改就會體現在所有繼承這個基模板的HTML頁面中體現。

Flask提供的模板引擎名為Jinja2,這里只作簡單的介紹,為我們所用的三個模板:base.html  entry.html  results.html

三個模板可以從這里下載http://python.itcarlow.ie/ed2/ch05/templates/

這個網址是我學習的書《Head First Python》提供的。

關於base.html

 

關於entry.html

用戶可以與這個HTML表單交互來提供web應用所需要的phrase和letters值。這個模板繼承了基模板,為名為body的塊提供了一個替代塊。

 

關於results.html

這個文件用來呈現搜索結果

 

在這里,對HTML的內容不做多的介紹,現在大概了解了它的一些基礎內容,會用即可。

從flask呈現模板

Flask提供了一個名為render_template的函數,如果指定一個模板名和所需的參數,調用這個函數時會返回一個HTML串。為了使用render_template,要把這個函數名增加到從flask模板導入的函數列表中,然后根據需要調用這個函數。把之前的web應用代碼文件hello_flask.py重命名一個更適合的名字:vsearch_for_web.py。並對該代碼進行以下修改:

  1. 導入render_template函數。

from flask import Flask , render_template

  1. 創建一個新的URL,這里是/entry。

@app.route(‘/entry’)

  1. 創建一個函數返回正確呈現的HTML。

def entry_page() -> ‘html’:

return render_template(‘entry.html’, the_title = ‘Welcome to search_for_letters on the web !’)

改完的代碼如下:

 1 from flask import Flask, render_template  2 from vsearch import search_for_letters  3 
 4 app = Flask(__name__)  5 
 6 @app.route('/')  7 def hello() -> str:  8 return 'hello world from Flask 
 9 
10 @app.route('/search') 11 def do_search() -> str: 12 return str(search_for_letters('life, the universe, and everything!', 'eriu,!')) 13 
14 @app.route('/entry') 15 def entry_page() -> 'html': 16 return render_template('entry.html', the_title = 'Welcome to search_for_letters on the web!') 17 
18 app.run()

 

需要在webapp文件夾里面創建如下的內容,這些內容都可以在剛才提供的網站里下載

Static文件夾里有一個名為hf.css的文件

現在已經准備好了,回到之前的命令提示符窗口(就是那個在webapp文件里面按住shift和右鍵然后點擊從此處運行的那個窗口),執行新的代碼:

python vsearch_for_web.py

窗口像剛才那樣出現了running

現在使用新的URL:http://127.0.0.1:5000/entry

瀏覽器出現了類似於草圖的窗口:

 

第一個對應/entry請求,第二個是對應瀏覽器對hf.css樣式表的請求有關。

 

雖然這個頁面看起來有些不美觀,但是我們現在先研究它能不能完成需要的功能。

現在輸入一個短語單擊do it!發生了一個錯誤:

 

看到服務器端窗口出現了一個內容:

 

關於http狀態碼

HTTP是允許web瀏覽器和服務器通信的協議。每個web請求都會生成一個http狀態碼響應。

狀態碼主要有五類:100類、200類、300類、400類和500類。

  100~199范圍內的狀態碼是信息消息:服務器在提供關於客戶端請求的詳細信息。

  200~299范圍內的狀態碼是成功消息:服務器已經接收、理解和處理客戶端的請求,一切正常。

  300~399范圍內的狀態碼是重定向消息:服務器通知客戶端請求可以在別處處理。

  400~499范圍內的狀態碼是客戶端錯誤消息:服務器從客戶端接收到一個它不理解也無法處理的請求,通常是客戶端的問題。

  500~599范圍內的狀態碼是服務器錯誤消息:服務器從客戶端接收到一個請求,但是服務器嘗試處理這個請求時失敗了,通常是服務器的問題。

HTTP方法中的GET和POST

瀏覽器通常使用GET方法從web服務器請求一個資源,這是HTTP默認的方法。

POST方法允許web瀏覽器向服務器通過HTTP發送數據,這與HTML<form>標記相關聯。

可以讓flask web應用從瀏覽器接收提交的數據,為此要在@app.route行上提供一個額外的參數——methods。

下面對vsearch_for_web.py中的代碼進行修改:第十行增加了POST方法

這與entry.html文件中的第7行代碼對應,注意參數名method的單數復數形式。

下面打開調試模式,將最后一行的代碼改為:app.run(debug=True)

現在我們的代碼應該如下所示:

 1 from flask import Flask, render_template  2 from vsearch import search_for_letters  3 
 4 app = Flask(__name__)  5 
 6 @app.route('/')  7 def hello() -> str:  8 return 'hello world from Flask'
 9 
10 @app.route('/search', methods = ['POST']) 11 def do_search() -> str: 12 return str(search_for_letters('life,the universe,and everything!','eriu,!')) 13 
14 @app.route('/entry') 15 def entry_page() -> 'html': 16 return render_template('entry.html', the_title = 'Welcome to search_for_letters on the web!') 17 
18 app.run(debug=True)

 

記住每次調試時都需要把之前打開的客戶端窗口重新啟動一次,現在已經是調試模式了:

下來試試我們的web應用交互:

點擊DO IT時會看到無論之前的phrase輸入什么,都會出現一個相同的結果:

這是因為之前代碼中有一些硬編碼值:life,the universe,and everything!','eriu,!

所以我們需要修改web應用的代碼來接收數據,然后才能進行新的操作。

Flask提供了一個內置對象:request,利用這個對象可以訪問所提交的數據。request對象包含一個名為form的字典屬性,form支持中括號記法,即要訪問表單中的一個數據可以把表單元素的名字放在中括號中:request.form[‘phrase’]和request.form[‘letters’]

這個對象仍需要導入才能使用。以下是新增加的內容:

第一行:

from flask import Flask, render_template, request

第十行:

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

def do_search() -> str:

  phrase = request.form['phrase']

  letters = request.form['letters']

  return str(search_for_letters(phrase, letters))

看一看命令提示窗口,flask調試器發現代碼有更改,會重啟web應用……

 

測試:

set()表示沒有搜索到letters

我們希望結果也生成一個類似的HTML表單。

回顧一下results.html模板的內容:

有四個變量:the_title,the_phrase,the_letters,the_results

對代碼進行修改:

def do_search() -> 'html':

  phrase = request.form['phrase']

  letters = request.form['letters']

  title = 'Here are your results:'

  results = str(search_for_letters(phrase, letters))

  return render_template('results.html', the_phrase = phrase, the_letters = letters, the_title = title, the_results = results, )

保存后在測試,發現結果頁面已經生成了HTML表單

就目前來看我們已經成功的構建了一個web應用,還使用了交互的HTML頁面,現在這個版本的web應用支持三個URL:/, /search, /entry

/地址會返回一個hello world from Flask消息,但是如果刪除這一個URL,再請求/時則會出現一個404 not found 錯誤(找不到對象確實聽起來不是很舒服),下面讓Flask把對/URL的所有請求重定向到/entry URL。調整hello函數是必要的。

重定向:

在第一行導入列表增加redirect;

修改hello函數:

這樣一來訪問http://127.0.0.1:5000/和http://127.0.0.1:5000/entry都是返回一個頁面。但是這個時候,一個請求指向/ URL,我們的web應用首先響應一個302重定向,然后web瀏覽器會發送另一個請求指向/entry URL,這會成功得到web應用的服務,但是每次指向/的一個請求就會變成兩個請求,顯然這樣是浪費資源的。

 

函數可以有多個URL

刪除hello函數,把@app.route('/')剪切到下面的@app.route('/entry')上面。

這樣就解決了剛才的浪費問題。

最終版本的代碼:

 1 from flask import Flask, render_template, request, redirect  2 from vsearch import search_for_letters  3 
 4 app = Flask(__name__)  5 
 6 @app.route('/search', methods = ['POST'])  7 def do_search() -> 'html':  8     phrase = request.form['phrase']  9     letters = request.form['letters'] 10     title = 'Here are your results:'
11     results = str(search_for_letters(phrase, letters)) 12     return render_template('results.html', the_phrase = phrase, the_letters = letters, the_title = title, the_results = results, ) 13 
14 @app.route('/') 15 @app.route('/entry') 16 def entry_page() -> 'html': 17     return render_template('entry.html', the_title = 'Welcome to search_for_letters on the web!') 18 
19 app.run(debug=True) 

 


免責聲明!

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



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