天天看點

Flask 入門0.web工作原理 與 flask關系1.安裝 Flask2.基本架構3.路由 @app.route('')4.變量規則5.URL建構6.HTTP方法:GET、POST等7.渲染模闆 render_template()8.Request對象9.Cookie10.會話Session case1.上傳表單case2.下載下傳上傳

目錄

0.web工作原理 與 flask關系

 B/S和C/S架構

 WEB工作原理

1.安裝 Flask

2.基本架構

3.路由 @app.route('')

4.變量規則

5.URL建構

6.HTTP方法:GET、POST等

7.渲染模闆 render_template()

8.Request對象

9.Cookie

10.會話Session

case1.上傳表單

case2.下載下傳上傳

0.web工作原理 與 flask關系

 B/S和C/S架構

- B/S:浏覽器/伺服器架構(用戶端需要更新才行)

- C/S:用戶端/伺服器架構(重新整理頁面即可更新)(可能會成為主流)

 WEB工作原理

用戶端 > 伺服器 > python(flask) > 資料庫(mysql)

1.安裝 Flask

Flask是 web架構,Flask主要包括 Werkzeug(負責業務處理) 和 Jinja2(安全方面) 兩個核心函數庫,Flask簡潔并易于擴充。

pip install flask
           
import flask
print(flask.__version__)
           

2.基本架構

@app.route(rule, options) 裝飾器告訴 Flask 觸發函數 的 路由(URL)。

rule 表示與該函數的URL綁定、

options 要轉發給基礎Rule對象的參數清單。

from flask import Flask
app = Flask(__name__) # 建立應用執行個體

# 視圖函數(路由)
@app.route("/")
def hello_world():
    return "Hello, World!"

if __name__ == '__main__':
   app.run(debug = True) # 啟動服務
           

儲存為 

app.py

。服務啟動預設使用5000端口,在浏覽器中打開 http://127.0.0.1:5000/ ,可以看到 Hello World! 字樣。

app.run(host, port, debug, options)

3.路由 @app.route('')

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

4.變量規則

通過把 URL 的一部分标記為 

<variable_name>

 就可以在 URL 中添加變量,标記的部分會作為關鍵字參數傳遞給函數。

from flask import Flask
app = Flask(__name__)

@app.route('/hello/<username>')
def hello(username):
    return f'Hello {username}!'

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

浏覽器中輸入http://127.0.0.1:5000/hello/Flask,則在浏覽器中的輸出如下

Hello Flask!

通過使用 

<converter:variable_name>

 ,可以選擇性的加上一個轉換器,為變量指定規則。

轉換器 說明

string

(預設值) 任何不包含斜杠的文本

int

正整數

float

正浮點數

path

比string

 多一個功能,可以包含斜杠

完整示例:

from flask import Flask
from markupsafe import escape

app = Flask(__name__)

@app.route('/hello/<username>')
def hello(username):
    return f'Hello {username}!'

@app.route('/path/<path:path>')
def show_path(path):
    return f'path {escape(path)}'

@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'Post {post_id}'

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

浏覽器輸入http://127.0.0.1:5000/integer/56,輸出

Integer: 56

浏覽器輸入http://127.0.0.1:5000/path/tmp/index.html,輸出

path: tmp/index.html

5.URL建構

url_for() 

用于建構指定函數的 URL。它把函數名稱作為第一個參數。它可以接受任意個關鍵字參數,每個關鍵字參數對應 URL 中的變量,未知變量 将添加到 URL 中作為查詢參數。

from flask import Flask, request, redirect
from flask import url_for

app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

@app.route('/login')
def login():
    print(f"in login function, request.values: {request.values}")
    return 'login'

@app.route('/user/<username>')
def profile(username):
    return f'{username}\'s profile'

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('profile', username='Xuan Yu'))
           

url_for('login')會生成對應的URL

/

/login

/user/Xuan%20Yu

6.HTTP方法:GET、POST等

方法 說明
GET 以未加密形式将資料發送到伺服器,常見
HEAD 和GET相同,但無響應體
POST 用于将HTML表單資料發送到伺服器,POST方法接收的資料不由伺服器緩存
PUT 用上傳的内容替換目标資源的所有目前表示
DELETE 删除由URL給出的目标資源的所有目前表示

預設情況 Flask路由隻回應 

GET

 請求。使用 

route()

 裝飾器的 

methods

 參數處理不同的 HTTP 方法。

目錄結構 templates/welcome.html。

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>HTTP方法</title>
</head>
<body>
    <form action = "http://localhost:5000/login" method = "post">
         <p>Enter Name:</p>
         <p><input type = "text" name = "username" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>
</body>
</html>
           

flask代碼:

from flask import Flask, redirect, url_for, request, render_template
app = Flask(__name__)

@app.route('/')
def index():
    return render_template('welcome.html')

@app.route('/welcome/<name>')
def welcome(name):
    return f'welcome {name}'

@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        user = request.form['username']
        return redirect(url_for('welcome', name=user))
    else:
        user = request.args.get('username')  # GET方法擷取資料
        return redirect(url_for('welcome', name=user))

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

如果是POST方法,則以下代碼從表單資料獲得的“username”參數的值:

user = request.form['username']

如果是GET方法,則通過以下代碼從表單資料獲得的“username”參數的值:

user = request.args.get('username')

args

是包含表單參數清單的字典對象,與’username’參數對應的值将傳遞到

/welcome

 URL中

/login?username=XuanYu

7.渲染模闆 

render_template()

目錄結構 templates/render_template.html

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>render_template</title>
</head>
<body>
    <h2>渲染模闆示範</h2>
    {{ my_int }}
    <br>
    {{ my_str }}
    <br>
    {{ my_list }}
    <br>
    {{ my_dict }}
    <hr>
    <h2>清單資料擷取</h2>
    {{ my_list[0] }}
    <br>
    {{ my_list.1 }}
    <hr>
    <h2>字典資料擷取</h2>
    {{ my_dict['name'] }}
    <br>
    {{ my_dict.age }}
    <hr>
    <h2>算術運算</h2>
    {{ my_list.0 + 10 }}
    <br>
    {{ my_list[0] + my_list.1 }}
</body>
</html>
           

flask代碼如下:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    int_ = 1024
    str_ = 'Hello World!'
    list_ = [1, 2, 3, 4, 5]
    dict_ = {'name': 'Kint', 'age': 23}
    # render_template方法:渲染模闆
    # 參數1: 模闆名稱  參數n: 傳到模闆裡的資料
    return render_template('render_template.html', my_int=int_, my_str=str_, my_list=list_, my_dict=dict_)

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

Flask 是使用 Jinja2 模闆引擎來渲染模闆,官方 Jinja2 模闆文檔。

8.Request對象

目錄檔案 templates/Request.html:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>Request</title>
</head>
<body>
    <form action="/login?a=1&b=2" method="post">
        <p>賬号: <input type="text" name="username"></p>
        <p>密碼: <input type="password" name="password"></p>
        <input type="submit">
    </form>
</body>
</html>
           

flask代碼:

from flask import Flask, request, render_template
import json

app = Flask(__name__)

@app.route('/')
def index():
    return render_template("Request.html")

@app.route('/login', methods=["GET", "POST"])
def login():
    print('request.method:\n', request.method)
    print('request.data:\n', request.data)
    print('request.request.args:\n', request.args)
    print("request.request.args.get('b'):\n", request.args.get('c'))
    print('request.form:\n', request.form)
    print("request.request.form.get('password'):\n", request.form.get('password'))
    print('request.values:\n', request.values)
    print('request.json:\n', request.json)
    print('request.cookies:\n', request.cookies)
    print('request.headers:\n', request.headers)
    return json.dumps(request.form) # 将MultiDict資料處理為JSON資料

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

在擷取MultiDict的值時,推薦使用request.form.get(key)而不直接使用request.form[key],前一種方式可以避免關鍵詞缺失而導緻的KeyError。

擷取各種路徑,URL為http://127.0.0.1:5000/login?a=1&b=2

print('url: ', request.url)

print('base_url: ', request.base_url)

print('host_url: ', request.host_url)

print('path: ', request.path)

print('full_path: ', request.full_path)

print('host: ', request.host)

輸出:

url:  http://127.0.0.1:5000/login?a=1&b=2

base_url:  http://127.0.0.1:5000/login

host_url:  http://127.0.0.1:5000/

path:  /login

full_path:  /login?a=1&b=2

host:  127.0.0.1:5000

9.Cookie

Flask中Cookie的處理步驟為:

  1. 使用Response對象的set_cookie()方法設定cookie
  2. 通過request.cookies的方式擷取cookies,傳回的是一個字典
  3. 使用Response對象的delete_cookie()方法設定cookie

templates檔案夾下get_cookie.html:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>擷取cookie</title>
</head>
<body>
    <h2>在服務端擷取cookie: <b>{{cookie}}</b></h2>
</body>
</html>
           

templates檔案夾下show_cookie_by_JQuery.html:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>設定cookie</title>
    <script src="../static/jquery-3.6.0.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
    <h2>在服務端設定cookie</h2>
    <h2>在用戶端通過JQuery讀取cookie: <b id='cookie'></b></h2>
</body>
<script>
    $('#cookie').text(document.cookie);
</script>
</html>
           

flask代下:

from flask import Flask, request, Response, render_template, make_response, redirect, url_for

app = Flask(__name__)

@app.route('/')
def index():
    # 重定向響應的URL
    return redirect(url_for('set_cookie'))  

# 設定cookie
@app.route('/set_cookie')
def set_cookie():
    html = render_template('show_cookie_by_JQuery.html')
    response = make_response(html)  # 設定響應體
    # response = Response(html)
    response.set_cookie('user', 'Kint')
    return response

# 擷取cookie
@app.route('/get_cookie')
def get_cookie():
    # 擷取關鍵字為user對應cookie的值
    cookie = request.cookies.get('user') 
    print(cookie)
    return render_template('get_cookie.html', cookie=cookie)


# 删除cookie
@app.route('/del_cookie')
def del_cookie():
    html = render_template('show_cookie_by_JQuery.html')
    response = Response(html)
    response.delete_cookie('user')
    return response

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

在set_cookie()函數中,首先渲染模闆檔案show_cookie_by_JQuery.html,通過make_response()方法設定響應體并傳回Response對象,然後設定cookie。兩種寫法作用相同:

response = make_response(html)  # 設定響應體

response = Response(html)

10.會話Session

與Cookie不同,Session資料存儲在伺服器上,用來存儲使用者的資訊 (例如登入狀态、使用者名稱)。Session 有一個唯一辨別 ID,對應一個使用者,在服務端使用 ID 可以查找到對應使用者的資料,故Flask應用程式需要一個定義的密鑰 SECRET_KEY。

簡單實作判斷使用者是否登入功能:

from flask import Flask, redirect, url_for, request, session

app = Flask(__name__)
app.secret_key = 'abc'

@app.route('/')
def index():
    if 'user' in session:
        # 擷取會話中的使用者資訊
        user = session.get('user')
        return '登入使用者是:' + user + '<br>' + "<b><a href = '/logout'>點選這裡登出</a></b>"
    return "<h3>暫未登入</h3><br>" + "<a href = '/login'></b>點選這裡登入</b></a>"

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 設定會話中的使用者資訊
        session['user'] = request.form['user']
        return redirect(url_for('index'))
    return '''
    <form action="" method="post">
        <p><input type="text" name="user"/></p>
        <p><input type="submit" value="登入"/></p>
    </form>
    '''

@app.route('/logout')
def logout():
    # 删除會話中的使用者資訊
    session.pop('user')
    return redirect(url_for('index'))

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

case1.上傳表單

/app.py

/templates

    /login.html

    /result.html

app.py:

from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def student():
   return render_template('login.html')


@app.route('/result',methods = ['POST', 'GET'])
def result():
   if request.method == 'POST':
      result = request.form #拿到前端傳輸的表單資料
      return render_template("result.html",result = result)


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

templates / login.html:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>case1.上傳表單資料—登入頁面</title>
</head>
<body>
    <form action="http://localhost:5000/result" method="POST">
         <p>Name <input type = "text" name = "Name" /></p>
         <p>Email <input type = "text" name = "Email" /></p>
         <p><input type = "submit" value = "submit" /></p>
    </form>
</body>
</html>
           

template / result.html:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>case1.上傳表單資料</title>
</head>
<body>
    <table border = 1>
        {% for key, value in result.items() %}
        <tr>
           <th> {{ key }} </th>
           <td> {{ value }}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>
           

case2.下載下傳上傳

/app.py

/templates

    /index.html

    /upload.html

/upload

    /download_sample.txt

app.py:

from flask import Flask, render_template, request, send_from_directory
from werkzeug.utils import secure_filename

import os

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'upload/'
# 上傳檔案大小限制為16M,如果超過會抛出異常
app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000  

@app.route('/')
def upload_file():
    return render_template('index.html')

@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        f = request.files['file']
        print(request.files)
        # secure_filename檢查用戶端上傳的檔案名,確定安全,注意檔案名稱不要全中文!!!
        f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename)))
        return render_template('upload.html')
    else:
        return render_template('index.html')

@app.route('/download/<filename>', methods=['GET', 'POST'])
def download(filename):
    # as_attachment=True 表示檔案作為附件下載下傳
    return send_from_directory('./upload', filename, as_attachment=True)

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

在upload函數中,f.save的作用是将檔案儲存到指定路徑中。在使用secure_filename檢驗上傳檔案名稱時,注意名稱盡量為英文!

在download函數中,send_from_directory方法将upload目錄下的指定檔案發送到用戶端,as_attachment=True表示檔案作為附件下載下傳。

在templates檔案夾下建立index.html檔案,代碼如下:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>執行個體2.上傳下載下傳檔案</title>
</head>
<body>
    <h3>上傳檔案</h3>
    <form action="http://localhost:5000/upload" method="POST" enctype="multipart/form-data">
        <input type="file" name="file"  />
        <input type="submit" value="送出" />
    </form>
    <h3>下載下傳檔案</h3>
    <a href="/download/download_sample.txt" target="_blank" rel="external nofollow" >download_sample.txt</a>
</body>
</html>
           

templates / upload.html:

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>case2.上傳成功頁面</title>
</head>
<body>
    <h3>檔案上傳成功!</h3>
</body>
</html>