亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

首頁 慕課教程 Flask 框架教程 Flask 框架教程 Flask 的 RESTful 架構的實例

Flask 的 RESTful 架構 的實例

在上一個小節中講解了 RESTful 架構的概念,本節通過具體的實例加深對 RESTful 架構的理解。

1. 程序功能和結構

1.1 程序功能

本小節使用 RESTful 架構完成一個在線通訊錄的程序,程序的界面如下:

圖片描述

程序提供如下功能:

  1. 在網站首頁展示所有的聯系人的信息,每個聯系人包含有姓名和電話兩個屬性;

  2. 添加新聯系人,在文本框中輸入姓名或者電話后,然后點擊 “新增” 按鈕完成;

  3. 修改聯系人,在文本框中修改姓名或者電話后,然后點擊 “修改” 按鈕完成;

  4. 刪除聯系人,通過點擊 “完成” 按鈕完成。

1.2 程序結構

程序包括 4 個源文件,如下所示:

文件 功能
app.py 后端服務程序,提供展示、新增、修改、刪除聯系人的功能
templates/index.html 頁面模板文件,提供展示、新增、修改、刪除聯系人的界面
static/style.css 對頁面模板進行美化的 css 文件
static/script.js 前端調用后端服務的 js 文件

1.3 源程序下載

2. RESTful 架構

2.1 資源

在通訊錄的 RESTful 架構中,聯系人被抽象為一種資源,使用 URI 表示如下:

http://localhost/users/123

每個聯系人都有自己的 URI,同時,每個聯系人有一個唯一的 id,/users/123 是 id 為 123 的聯系人對應的 URI。

2.2 訪問資源的 URI

客戶端可以新增、修改、刪除聯系人,相應的 URI 如下:

HTTP 方法 行為 URI
POST 新增聯系人 http://localhost/users
PUT 修改 id 為 123 的聯系人 http://localhost/users/123
DELETE 刪除 id 為 123 的聯系人 http://localhost/users/123

3. 后端服務 app.py

3.1 引入相關模塊

#!/usr/bin/python3
from flask import Flask, render_template, request, jsonify
from datetime import timedelta

app = Flask(__name__)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = timedelta(seconds=1) 

在第 2 行,從 flask 模塊中引入函數 jsonify,該函數將 JSON 格式的數據轉換為字符串。

在第 6 行,配置 Flask 應用的 SEND_FILE_MAX_AGE_DEFAULT 屬性,該屬性設置靜態文件緩存過期時間,在這個程序中將其設置為 1 秒,timedelta(seconds=1) 表示長度為 1 秒的時間。

這個程序使用了兩個靜態文件 style.css 和 script.js,默認情況下,Flask 框架會緩存靜態文件(12 個小時),如果在服務端更新了靜態文件,瀏覽器訪問靜態文件無法及時獲得更新。為了方便調試程序,在這里配置靜態文件緩存過期時間為 1 秒。

3.2 聯系人數據庫

class User:
    nextId = 0 

    def __init__(self, name, phone):
        self.id = User.nextId
        User.nextId += 1
        self.name = name
        self.phone = phone

tom = User('tom', '10086')
jerry = User('jerry', '12306')
users = [tom, jerry]

使用類 User 描述一個聯系人,每個聯系人包含有 3 個屬性:id、name、phone。

User.nextId 記錄了下一個可用的用戶 id,在 User.__init__ 中,使用 User.nextId 作為當前新建用戶的 id,然后使用 User.nextId += 1 更新下一個可用的用戶 id。

在第 10 行和第 11 行,創建了兩個聯系人: tom 和 jerry。使用全局變量 users 記錄全部的聯系人,將 tom 和 jerry 加入到列表 users 中。

3.3 展示所有的聯系人

@app.route('/')
def index():
    return render_template('index.html', users = users)

設置頁面路徑 / 的處理函數 index,函數 index 渲染模板文件 index.html。將全局變量 users 傳遞給頁面模板,users 中記錄了所有的聯系人,因此頁面中會展示所有的聯系人。

3.4 新增聯系人

@app.route('/users', methods=['POST'])
def addUser():
    name = request.json['name']
    phone = request.json['phone']

    user = User(name, phone)
    users.append(user)

    return jsonify({'error': None});

通過 POST 方法訪問頁面路徑 /users 的處理函數是 addUser,在 RESTful 架構中,POST /users 表示新增一個聯系人。

在第 3 行和第 4 行,request.json 是一個字典,記錄了客戶端發送的 JSON 格式的參數:聯系人的姓名和電話;在第 6 行和第 7 行,將新建的聯系人加入到全局變量 users;最后,使用 jsonify 將 JSON 格式的數據轉換為字符串,{‘error’: None} 表示操作成功。

3.5 更新聯系人

@app.route('/users/<int:userId>', methods=['PUT'])
def updateUser(userId):
    name = request.json['name']
    phone = request.json['phone']

    for user in users:
        if user.id == userId:
            user.name = name
            user.phone = phone
            break

    return jsonify({'error': None});

在第 1 行,通過 PUT 方法訪問頁面路徑 /users/userId 的處理函數是 updateUser,在 RESTful 架構中,PUT /users/userId 表示新增一個聯系人。

/users/<int:userId> 表示了一個動態路由,它可以匹配如下的路徑:

  • /users/1,id 為 1 的聯系人對應的 URI
  • /users/2,id 為 2 的聯系人對應的 URI
  • /users/3,id 為 3 的聯系人對應的 URI

對符號 <int:userId> 的解釋如下:

  • int 表示匹配整數,/users/<int:userId> 可以匹配 /users/1 (1 是一個整數),不能匹配 /users/tom (tom 不是整數);
  • userId 表示匹配的值,/users/<int:userId> 和 /users/1 匹配后,userId 為 1,它作為參數被傳遞給頁面處理函數 updateUser。

在第 3 行和第 4 行,request.json 是一個字典,記錄了客戶端發送的 JSON 格式的參數:聯系人的姓名和電話;在第 6 行,在全局變量 users 根據 userId 查找指定的 user 并更新;最后,使用 jsonify 將 JSON 格式的數據轉換為字符串,{‘error’: None} 表示操作成功。

3.6 刪除聯系人

@app.route('/users/<int:userId>', methods=['DELETE'])
def deleteUser(userId):
    index = 0
    for user in users:
        if user.id == userId:
            del users[index]
            break
        index += 1

    return jsonify({'error': None});

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

在第 1 行,通過 DELETE 方法訪問頁面路徑 /users 的處理函數是 deleteUser,在 RESTful 架構中,DELETE /users/userId 表示新增一個聯系人。

/users/<int:userId> 表示了一個動態路由,在 3.5 小節進行了詳細的解釋。

在第 4 行,根據 userId 在全局變量 users 中查找相應的 user 并刪除;最后,使用 jsonify 將 JSON 格式的數據轉換為字符串,{‘error’: None} 表示操作成功。

4. 模板文件 templates/index.html

模板文件 templates/index.html 是網站的首頁面,分為 3 個部分描述。

4.1 引入 css 和 js 文件

<html>
<head>
<meta charset='utf-8'>
<script src="https://lib.baomitu.com/jquery/2.2.4/jquery.min.js"></script>
<link href="{{url_for('static', filename='style.css')}}" rel="stylesheet">
<script src="{{url_for('static', filename='script.js')}}"></script>
</head>

在第 4 行,引入庫 jquery,在前端需要使用 jquery 的 ajax 功能調用后端服務。

在第 5 行,引入靜態文件 style.css,函數 url_for(‘static’, filename=‘style.css’) 的輸出為 ‘/static/style.css’。

在第 6 行,引入靜態文件 script.js,函數 url_for(‘static’, filename=‘script.js’) 的輸出為 ‘/static/script.js’。

4.2 新增聯系人

<body>
<h1>通訊錄</h1>
<div class="row">
  <input type="text" placeholder='姓名'>
  <input type="text" placeholder='電話'>
  <span class="button" onclick="addUser(this);">增加</span>
</div>

新增聯系人的界面包含 3 個部分:

  • 一個文本字段用于填寫姓名;
  • 一個文本字段用于填寫電話;
  • 一個按鈕,用于增加聯系人,設置按鈕的 onclick 函數,點擊按鈕時執行函數 addUser(this),其中 this 指向按鈕對應的 DOM 元素。

4.3 展示所有的聯系人

<div>
  {% for user in users %}
  <div class="row">
    <input type="text" value="{{user.name}}" placeholder='姓名'>
    <input type="text" value="{{user.phone}}" placeholder='電話'>
    <span class="button" onclick="updateUser(this, {{user.id}});">修改</span>
    <span class="button" onclick="deleteUser(this, {{user.id}});">刪除</span>
  </div>
  {% endfor %}
</div>
</body>
</html>

Flask 程序將全局變量 users 傳遞給渲染模板文件 templates/index.html,全局變量 users 包含有所有的聯系人。

在第 2 行,逐行展示所有的聯系人,每個聯系人包括 4 個部分:

  • 一個文本字段展示姓名,值為 user.name
  • 一個文本字段展示電話,值為 user.phone;
  • 一個按鈕,用于修改聯系人,點擊按鈕時執行函數 updateUser(this),其中 this 指向按鈕對應的 DOM 元素;
  • 一個按鈕,用于刪除聯系人,點擊按鈕時執行函數 updateUser(this),其中 this 指向按鈕對應的 DOM 元素。

設置按鈕的 onclick 函數,點擊按鈕時執行函數 addUser(this),其中 this 指向按鈕對應的 DOM 元素。

5. 美化界面 static/style.css

.button {
    color: white;
    background-color: black;
    padding-left: 2px;
    padding-right: 2px;
    border: 1px solid black;
    border-radius: 4px;
    cursor: pointer;
}

.row {
    margin-top: 4px;
    margin-bottom: 4px;
}

樣式 .button 用于美化按鈕,在第 2 行,設置 button 的背景和前景;在第 6 行,設置 button 的邊框;在第 7 行,設置 button 為圓角。

樣式 .row 用于設置聯系人之間的行間距。

6. 前端調用后端服務 static/script.js

6.1 配置 ajax

function ajaxError()
{
    alert('ajax error');
}

function ajaxSuccess(result)
{
    if (result.error) {
        alert('操作失敗');
        return;
    }
    location.reload();
}

在 RESTful 架構中,客戶端使用 ajax 技術請求服務端的服務。當 ajax 請求失敗時,調用 ajaxError,提示用戶 ajax 請求服務失??;當 ajax 請求成功時,調用 ajaxSuccess,提示用戶 ajax 請求服務成功。

在網站的首頁展示所有的聯系人,當新增、修改、刪除聯系人后,需要刷新首頁面,因此,在第 12 行,當 ajax 調用服務成功后,需要 location.reload() 刷新頁面,從服務端重新加載所有的聯系人。

6.2 新增聯系人

function addUser(button)
{
    var children = $(button).parent().children();
    var name = children.eq(0).val();
    var phone = children.eq(1).val();
    var data = JSON.stringify({'name': name, 'phone': phone});
    
    $.ajax({
        'url': '/users',
        'type': 'POST',
        'contentType': 'application/json',
        'data': data,
        'dataType': 'json',
        'error': ajaxError,
        'success': ajaxSuccess
    });
}

點擊 “新增” 按鈕后,執行函數 addUser(button),button 指向的是 “新增” 按鈕。在 templates/index.html 中,按鈕、聯系人姓名、聯系人電話于相同的 DIV 中,如下所示:

<div class="row">
  <input type="text" placeholder='姓名'>
  <input type="text" placeholder='電話'>
  <span class="button" onclick="addUser(this);">增加</span>
</div>

在第 3 行到第 5 行,表達式的含義如下所示:

表達式 含義
$(button).parent() 指向按鈕的父節點
$(button).parent().children() 表示 div 的 3 個子節點
children.eq(0) 指向聯系人姓名
children.eq(1) 指向聯系人電話
children.eq(2) 指向新增按鈕

在第 4 行,根據聯系人的姓名和電話創建一個新聯系人,將它作為參數、調用后端新增聯系人的服務。

在第 8 行,通過 jquery 的 ajax 函數調用后端服務,設置 url 為 ‘/users/’、type 為 ‘POST’ ,表示 RESTful 架構下的新增聯系人。

6.3 更新聯系人

function updateUser(button, userId)
{
    var children = $(button).parent().children();
    var name = children.eq(0).val();
    var phone = children.eq(1).val();
    var data = JSON.stringify({'name': name, 'phone': phone});
    
    $.ajax({
        'url': '/users/' + userId,
        'type': 'PUT',
        'contentType': 'application/json',
        'data': data,
        'dataType': 'json',
        'error': ajaxError,
        'success': ajaxSuccess
    });
}

點擊 “更新” 按鈕后,執行函數 updateUser(button, userId),button 指向的是 “新增” 按鈕,userId 是需要更新的聯系人 id。

在第 3 行到第 5 行,獲取需要聯系人的姓名和電話,使用了和 6.2 小節相同的方法,請參考 6.2 小節。

在第 8 行,通過 jquery 的 ajax 函數調用后端服務,設置 url 為 ‘/users/userId’、type 為 ‘PUT’ ,表示 RESTful 架構下的更新聯系人。

6.4 刪除聯系人

function deleteUser(button, userId)
{
    var children = $(button).parent().children();
    var data = JSON.stringify({});
    
    $.ajax({
        'url': '/users/' + userId,
        'type': 'DELETE',
        'contentType': 'application/json',
        'data': data,
        'dataType': 'json',
        'error': ajaxError,
        'success': ajaxSuccess
    });

}

點擊 “刪除” 按鈕后,執行函數 deleteUser(button, userId),button 指向的是 “新增” 按鈕,userId 是需要更新的聯系人 id。

在第 3 行到第 5 行,獲取需要聯系人的姓名和電話,使用了和 6.2 小節相同的方法,請參考 6.2 小節。

在第 8 行,通過 jquery 的 ajax 函數調用后端服務,設置 url 為 ‘/users/userId’、type 為 ‘DELETE’ ,表示 RESTful 架構下的刪除聯系人。

7. 小結

本節使用 RESTful 架構完成一個在線通訊錄的程序,通過實例講解了 RESTful 架構的設計與實現,使用思維導圖概括如下:

圖片描述