【Python Flask 入门指南】轻量级网页框架教学 | 5 行程序码 x 架设网站

目录

  • 前言 : 五行程序码
  • Python Flask - Hello World
  • 网页模版 - Html 回传
  • 资料交换 - Form 表单提交 与 Ajax 资料交换
  • 开发配置 - 外网访问与热部署

前言 : 五行程序码

Python Flask 是一种轻量级的网页框架,只要五行程序码,就可以架设网页服务器 :

步骤一 : 安装 Flask 套件

$ pip install Flask

步骤二 : 将以下代码存档为 app.py

from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello, World!"

步骤三 : 终端机指令执行

$ flask run 

出现「Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)」的文字

浏览器访问 127.0.0.1:5000,出现 Hello World ,代表架设完成 !

001


What does "micro" mean?

在 Flask 的官网,对於 「micro」 有这样的定义 :

轻量并不代表缺少功能,而是在保持核心简单的情况下,留有扩展空间。
做法就是不为你事先做出决定,只会包含「你需要的一切,而没有你不需要的」。

Python Flask 入门指南

除了说明上述五行程序码代表的含义,还会延伸几项後端开发常见的配置:

  • URL 路由 - 注解注册
  • Html 回传 - 网页模版
  • Web API - 资料交换

从 Flask 入门网站开发,可以带你快速的了解,网页框架通常会具备的功能,以及累积网站开发後端的知识。

对於後续要了解 Python 在网路领域,相关的技术与应用,例如: 爬虫的原理或者资料库的数据分析,

都可以大幅提升学习的效率。


源代码,下载

章节中的程序码范例


Python Flask - Hello World

Python 版本建议 3.4 以上,内置的 pip 工具可以节省很多时间

Hello World 范例

from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello, World!"

第一行 : from flask import Flask

另外一种更常见的 import 方式,可以简化第二行的建构式宣告。

方法一:
import Flask 
app = flask.Flask(__name__)

方法二:
from flask import Flask
app = Flask(__name__)

方法二为官网的范例。

第二行 : app = Flask(__name__)

Flask 类别 初始化时 传入的 __name__ 参数,代表当前模组的名称。
是固定用法,以便让 Flask 知道在哪里寻找资源。
(例如: 模板和静态文件)

第三行 : @app.route("/")

装饰器是告诉 Flask,哪个 URL 应该触发我们的函式。

斜线代表的就是网站的根目录,可以叠加。

例如: 新增一个 /hello 的位址

@app.route("/")
@app.route("/hello")
def hello():
    return "Hello, World!"

网站访问首页与/hello,呈现的同样是 hello 函式,回传的 Hello World 文字。
  • def hello(): : 被触发的函式 第四行
  • return "Hello, World!" : 函式回传的文字字串,也等於 Web API 回传的内容。第五行

flask run 指令

官方范例,档名为 app.py 使用的是 flask run 指令,可以直接启动网站。

在日常的开发中,可以再加上 python 的 main 方法,
执行 app.run() 函式,执行网页服务器的启动动作。

调整後 : hello-world.py

# save this as app.py
import flask
app = flask.Flask(__name__)

@app.route("/")
@app.route("/hello")
def hello():
    return "Hello, World!"

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

注册路由

除了固定的导向位址,URL 也可以成为函式接收的参数

routing.py

@app.route('/data/appInfo/<name>', methods=['GET'])
def queryDataMessageByName(name):
    print("type(name) : ", type(name))
    return 'String => {}'.format(name)

<name> 代表接收 name 参数为 字串型态

  • 访问 : http://127.0.0.1:5000/data/appInfo/FlaskSE
  • 打印 : type(name) : <class 'str'>
  • 网页 : String => FlaskSE
@app.route('/data/appInfo/id/<int:id>', methods=['GET'])
def queryDataMessageById(id):
    print("type(id) : ", type(id))
    return 'int => {}'.format(id)
  • 访问 : http://127.0.0.1:5000/data/appInfo/id/5
  • 打印 : type(id) : <class 'int'>
  • 网页 : int => 5
@app.route('/data/appInfo/version/<float:version>', methods=['GET'])
def queryDataMessageByVersion(version):
    print("type(version) : ", type(version))
    return 'float => {}'.format(version)
  • 访问 : http://127.0.0.1:5000/data/appInfo/version/1.01
  • 打印 : type(version) : <class 'float'>
  • 网页 : float => 1.01

网页模版 - Html 回传

Python Flask 使用 Jinja2 的模板引擎

最简单的网页格式

@app.route('/text')
def text():
    return '<html><body><h1>Hello World</h1></body></html>'
  • 网页显示 : H1 大标题的 Hello World 元素
  • 简单的格式还可以,复杂一点,回传 html 档案会较为理想。

templates 资料夹

在 python 执行档的目录下,创建 templates 资料夹,html 档案放置於此

  • /render.py
  • /templates
    • /home.html
    • /page.html
    • /static.html

render.py

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

templates/home.html

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>Home</title>
</head>
<body>
        <h1>My Website Text</h1>
        <table border="1">
                <tr>
                        <td>Text Text Text</td>
                        <td>Text Text Text</td>
                        <td>Text Text Text</td>
                </tr>
                <tr>
                        <td>Text Text Text</td>
                        <td>Text Text Text</td>
                        <td>Text Text Text</td>
                </tr>
                <tr>
                        <td>Text Text Text</td>
                        <td>Text Text Text</td>
                        <td>Text Text Text</td>
                </tr>
        </table>
</body>
</html>
  • 访问 : http://127.0.0.1:5000/home
  • 网页 :
    002

Jinja2 模板引擎

API 返回网页时,可以做更多的事情

先看完整的程序码,接续有说明。

render.py

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/text')
def text():
    return '<html><body><h1>Hello World</h1></body></html>'

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

@app.route('/page/text')
def pageText():
    return render_template('page.html', text="Python Flask !")

@app.route('/page/app')
def pageAppInfo():
    appInfo = {  # dict
        'id': 5,
        'name': 'Python - Flask',
        'version': '1.0.1',
        'author': 'Enoxs',
        'remark': 'Python - Web Framework'
    }
    return render_template('page.html', appInfo=appInfo)

@app.route('/page/data')
def pageData():
    data = {  # dict
        '01': 'Text Text Text',
        '02': 'Text Text Text',
        '03': 'Text Text Text',
        '04': 'Text Text Text',
        '05': 'Text Text Text'
    }
    return render_template('page.html', data=data)

@app.route('/static')
def staticPage():
    return render_template('static.html')

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

templates/page.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Template - Page</title>
</head>

<body>
    <h1>Template - Page </h1>
    <h2>{{text}}</h2>

    {% if appInfo != undefined %}

    <h2>AppInfo : </h2>
    <p>id : {{appInfo.id}}</p>
    <p>name : {{appInfo.name}}</p>
    <p>version : {{appInfo.version}}</p>
    <p>author : {{appInfo.author}}</p>
    <p>remark : {{appInfo.remark}}</p>
    {% endif %}

    {% if data != undefined %}
    <h2>Data : </h2>
    <table border="1">
        {% for key, value in data.items() %}
        <tr>
            <th> {{ key }} </th>
            <td> {{ value }} </td>
        </tr>
        {% endfor %}
    </table>
    {% endif %}
</body>

</html>

API 附带参数: @app.route('/page/text')

render.py

@app.route('/page/text')
def pageText():
    return render_template('page.html', text="Python Flask !")
  • render_template() 函式 : 第二个参数可以附带资料内容

templates/page.html

<h1>Template - Page </h1>
<h2>{{text}}</h2>
  • text 参数 : 使用两个大括号 {{ text }} 就可以将资料显示在画面上

API 字典型态与页面条件式 : @app.route('/page/app')

render.py

@app.route('/page/app')
def pageAppInfo():
    appInfo = {  # dict
        'id': 5,
        'name': 'Python - Flask',
        'version': '1.0.1',
        'author': 'Enoxs',
        'remark': 'Python - Web Framework'
    }
    return render_template('page.html', appInfo=appInfo)
  • 不同的路由路径,传递相同的网页模版 :
    • @app.route('/page/app')
    • render_template('page.html', appInfo=appInfo)
  • appInfo 参数 : 字典型态的变数,将更多的资料,在同一时间传递。

templates/page.html

{% if appInfo != undefined %}
<h2>AppInfo : </h2>
<p>id : {{appInfo.id}}</p>
<p>name : {{appInfo.name}}</p>
<p>version : {{appInfo.version}}</p>
<p>author : {{appInfo.author}}</p>
<p>remark : {{appInfo.remark}}</p>
{% endif %}
  • 模板引擎,前端画面条件式语法 :
    • {% if boolean %}
    • {% endif %}
    • if appInfo != undefined : 如果 appInfo 有资料,html 标签内容生效
  • {{appInfo.object}} : 字典参数取用资料方法,同样两个大括号包覆後生效。

API : 字典型态与页面回圈

render.py

@app.route('/page/data')
def pageData():
    data = {  # dict
        '01': 'Text Text Text',
        '02': 'Text Text Text',
        '03': 'Text Text Text',
        '04': 'Text Text Text',
        '05': 'Text Text Text'
    }
    return render_template('page.html', data=data)
  • 不同的路由路径,传递相同的网页模版 :
    • @app.route('/page/data')
    • return render_template('page.html', data=data)
  • data 参数 : 字典型态的变数,与上一个相同,将更多的资料,同时间传递。

templates/page.html

{% if data != undefined %}
<h2>Data : </h2>
<table border="1">
    {% for key, value in data.items() %}
    <tr>
        <th> {{ key }} </th>
        <td> {{ value }} </td>
    </tr>
    {% endfor %}
</table>
{% endif %}
  • 模板引擎,前端画面条件式语法 : 与上一个相同
    • {% if boolean %}
    • {% endif %}
  • 模板引擎,for 回圈语法 : 将表格与参数内的资料,同时呈现出来
    • {% for key, value in data.items() %}
    • {{ key }} : 回圈 key 值
    • {{ value }} : 回圈 value 值
    • {% endfor %}

static 资料夹

在 python 执行档的目录下,创建 static 资料夹,.js 与 .css 档案放置於此

  • /render.py
  • /templates
    • /home.html
    • /page.html
    • /static.html
  • /static
    • /script.js
    • /style.css

前端开发的 javascript 与 css 档案必须放在 static 资料夹才会生效。


static.py

@app.route('/static')
def staticPage():
    return render_template('static.html')

static/script.js

function sayHello(){
        alert("Hello World");
}

templates/static.html

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>Static - Page</title>
</head>
<body>
        <h1>Template - Page</h1>
        <button id="btnHello" onClick="sayHello()">Say Hello</button>
        <!-- <script src="../static/script.js"></script> -->
        <script type = "text/javascript" 
         src = "{{ url_for('static', filename = 'script.js') }}" ></script>
</body>
</html>
  • 如果 src 的路径不为 static
    • 点击 button 不会有反应
    • 终端机显示 http 404,表示找不到资源
  • {{ url_for('static', filename = 'script.js') }}
    • 另外一种模板引擎的写法,url_for 是转址的函式
    • 第一个参数不动,调整 filename 参数可以使用其他资源

资料交换 - Form 表单提交 与 Ajax 资料交换

结合路由注册与网页模版,完整实现前端与後端的资料交换

前端 : 示范两种

  1. Html - Form 表单提交
  2. jQuery - Ajax 资料交换

後端 : JSON 格式

  • 读写实际的文件,模拟资料持久化

Html - Form 表单提交

同样先看代码,接续代码说明

form.py

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

@app.route('/form')
def formPage():
    return render_template('Form.html')

@app.route('/submit', methods=['POST', 'GET'])
def submit():
    if request.method == 'POST':
        user = request.form['user']
        print("post : user => ", user)
        return redirect(url_for('success', name=user, action="post"))
    else:
        user = request.args.get('user')
        print("get : user => ", user)
        return redirect(url_for('success', name=user, action="get"))

@app.route('/success/<action>/<name>')
def success(name, action):
    return '{} : Welcome {} ~ !!!'.format(action, name)

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

templates/form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Form - Submit</title>
</head>
<body>
    <h2>POST</h2>
    <form action="/submit" method="post">
        <h2>Enter Name:</h2>
        <p><input type="text" name="user" /></p>
        <p><input type="submit" value="submit" /></p>
    </form>
    <h2>GET</h2>
    <form action="/submit" method="get">
        <h2>Enter Name:</h2>
        <p><input type="text" name="user" /></p>
        <p><input type="submit" value="submit" /></p>
    </form>
</body>
</html>

前端 : Form 表单提交

templates/form.html

<form action="/submit" method="post">
    <h2>Enter Name:</h2>
    <p><input type="text" name="user" /></p>
    <p><input type="submit" value="submit" /></p>
</form>
<h2>GET</h2>
<form action="/submit" method="get">
    <h2>Enter Name:</h2>
    <p><input type="text" name="user" /></p>
    <p><input type="submit" value="submit" /></p>
</form>
  • <form></form> : 两个 form 表单元素
  • action : 提交目标,也就是路由的 URL
  • method : http 常见的提交方法,这里分别实作 get 与 post 方法
  • <input type="text" name="user" /> : 传递表单参数 name
  • <input type="submit" value="submit" /> : html 元素,form 提交按钮

後端 : 网页模版与资料接口

form.py

@app.route('/form')
def formPage():
    return render_template('Form.html')
  • form.html 的路由注册与模板回传
from flask import ... , request, redirect, url_for
@app.route('/submit', methods=['POST', 'GET'])
def submit():
    if request.method == 'POST':
        user = request.form['user']
        print("post : user => ", user)
        return redirect(url_for('success', name=user, action="post"))
    else:
        user = request.args.get('user')
        print("get : user => ", user)
        return redirect(url_for('success', name=user, action="get"))
  • @app.route('/submit', methods=['POST', 'GET'])
    • @app.route('/submit', ... ) : 注册路由为 /submit
    • @app.route( ... , methods=['POST', 'GET']): 接收 POST 与 GET 方法
  • request : import 导入,物件的 method 成员,可以知道前端传递的是使用 HTTP 的哪种方法
  • if request.method == 'POST': : POST 方法必须使用 request.form 的变数
  • else: : GET 方法必须使用 request.args 的变数
  • return redirect(url_for('success', name=user, action="post"))
    • import 导入 redirect 与 url_for 用於接收资料成功後,转址的功能
    • redirect() 函式包含 url_for() 函式,是固定用法
    • url_for 字串的参数为路由定义的 API 函式,後方的参数为要传送的资料内容
      • 这边的范例,就是转址到 success() 函式
      • 接收使用者名称 name 与 http 方法 action
@app.route('/success/<action>/<name>')
def success(name, action):
    return '{} : Welcome {} ~ !!!'.format(action, name)
  • suceesss() 函式 : 回传 字串格式化的文字

完整 form 表单提交 与 接收成功後转址流程

003


jQuery - Ajax 资料交换

同样先看代码,接续代码说明

文件结构

  • /ajax.py
  • /templates
    • /data.html
  • /static
    • /jquery-3.6.0.min.js
    • /data
      • /input.json
      • /message.json

ajax.py

from flask import Flask, render_template, request, jsonify, json
app = Flask(__name__)

@app.route('/data')
def webapi():
    return render_template('data.html')

@app.route('/data/message', methods=['GET'])
def getDataMessage():
    if request.method == "GET":
        with open('static/data/message.json', 'r') as f:
            data = json.load(f)
            print("text : ", data)
        f.close
        return jsonify(data)  # 直接回传 data 也可以,都是 json 格式

@app.route('/data/message', methods=['POST'])
def setDataMessage():
    if request.method == "POST":
        data = {
            'appInfo': {
                'id': request.form['app_id'],
                'name': request.form['app_name'],
                'version': request.form['app_version'],
                'author': request.form['app_author'],
                'remark': request.form['app_remark']
            }
        }
        print(type(data))
        with open('static/data/input.json', 'w') as f:
            json.dump(data, f)
        f.close
        return jsonify(result='OK')

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

data.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="../static/jquery-3.6.0.min.js"></script>
    <title>WebAPI</title>
</head>
<body>
    <h1>DATA : API</h1>
    <h2>API : GET</h2>
    <button id='btnGet'>GET</button>
    <hr>
    <h2>API : POST</h2>
    <p>APP_ID :
        <input id="app_id" name="app_id" type="number" />
    </p>
    <p>APP_NAME :
        <input id="app_name" name="app_name" type="text" />
    </p>
    <p>APP_VERSION :
        <input id="app_version" name="app_version" type="text" />
    </p>
    <p>APP_AUTHOR :
        <input id="app_author" name="app_author" type="text" />
    <p>APP_REMARK :
        <input id="app_remark" name="app_remark" type="text" />
    </p>
    <button id="btnPost">POST</button>
    <hr>
    <h3>Console : </h3>
    <div id="console"></div>
    <script>
        $(function () {
            var $btnGet = $('#btnGet');
            var $console = $('#console');
            var $btnPost = $('#btnPost');
            var $edtAppId = $('#app_id');
            var $edtAppName = $('#app_name');
            var $edtAppVersion = $('#app_version');
            var $edtAppAuthor = $('#app_author');
            var $edtAppRemark = $('#app_remark');
            $btnGet.off('click').on('click', function () {
                $.ajax({
                    url: '/data/message',
                    data: {},
                    type: 'GET',
                    success: function (data) {
                        $console.text("");
                        $console.append("data[id] : " + data.appInfo.id + "---");
                        $console.append("data[name] : " + data.appInfo.name + "---");
                        $console.append("data[version] : " + data.appInfo.version + "---");
                        $console.append("data[author] : " + data.appInfo.author + "---");
                        $console.append("data[remark] : " + data.appInfo.remark + "---");

                        $edtAppId.val(data.appInfo.id);
                        $edtAppName.val(data.appInfo.name);
                        $edtAppVersion.val(data.appInfo.version);
                        $edtAppAuthor.val(data.appInfo.author);
                        $edtAppRemark.val(data.appInfo.remark);

                    },
                    error: function (xhr) {
                        alert('Ajax request 发生错误');
                    }
                });
            })
            $btnPost.off('click').on('click',function(){
                $.ajax({
                    url: '/data/message',
                    data: {
                        "app_id" : $edtAppId.val() , 
                        "app_name" : $edtAppName.val(),
                        "app_version" : $edtAppVersion.val(),
                        "app_author" : $edtAppAuthor.val(),
                        "app_remark" : $edtAppRemark.val(),

                    },
                    type: 'POST',
                    success: function (data) {
                        $console.text("result = ");
                        $console.append(data.result);
                    },
                    error: function (xhr) {
                        alert('Ajax request 发生错误');
                    }
                });
            });
        });
    </script>
</body>
</html>

/static/jquery-3.6.0.min.js

jQuery 函式库,Ajax() 函式会使用到

/data/input.json

空白内容,用於写入资料的目标档案

/data/message.json

{
    "appInfo" : {     
        "id" : 5,
        "name" : "Python - Flask" ,
        "version" : "1.0.1" ,
        "author" : "author" ,
        "remark" : "Python - Web Framework"
    }
}
  • JSON 格式资料,用於读取资料的目标档案

後端 : 网页模版与资料接口

ajax.py

@app.route('/data')
def webapi():
    return render_template('data.html')
  • data.html 的路由注册与模板回传
@app.route('/data/message', methods=['GET'])
def getDataMessage():
    if request.method == "GET":
        with open('static/data/message.json', 'r') as f:
            data = json.load(f)
            print("text : ", data)
        f.close
        return jsonify(data)  # 直接回传 data 也可以,都是 json 格式
  • @app.route('/data/message', methods=['GET']) : 注册路由为 data/message,接收 Get 方法
  • with open('static/data/message.json', 'r') as f: : 读取静态文件 data 资料夹下的 message.json 档案
    • data = json.load(f) : 使用 json 物件,读取 message.json 档案内的 json 文字格式。
    • f.close : 读取完成後,关闭文件。
  • return jsonify(data) : data 为 JSON 格式的字串,可以直接回传,可以使用 jsonify() 函式,序列化後再进行传递。
@app.route('/data/message', methods=['POST'])
def setDataMessage():
    if request.method == "POST":
        data = {
            'appInfo': {
                'id': request.form['app_id'],
                'name': request.form['app_name'],
                'version': request.form['app_version'],
                'author': request.form['app_author'],
                'remark': request.form['app_remark']
            }
        }
        print(type(data))
        with open('static/data/input.json', 'w') as f:
            json.dump(data, f)
        f.close
        return jsonify(result='OK')
  • @app.route('/data/message', methods=['POST']) : 注册路由为 data/message,接收 Get 方法
  • data = { ... } : 从 request 取得前端的提交的表单内容,储存在字典型态的变数中
  • with open('static/data/input.json', 'w') as f: : 写入静态文件 data 资料夹下的 input.json 档案
    • json.dump(data, f) : 使用 json 物件,写入 json 文字格式到 input.json 档案。
    • f.close : 读取完成後,关闭文件。
  • return jsonify(result='OK') : 使用 jsonify() 函式,序列化 JSON 格式的字串,回传 resulut = OK 的内容

前端 : jQuery 按钮,Ajax 请求 Get 与 Post

<!DOCTYPE html>
<html lang="en">
<head>
    ...
    <script src="../static/jquery-3.6.0.min.js"></script>
    ...
</head>
<body>
...
</body>
</html>

  • Ajax 会使用到 jQuery 的框架,导入时 要注意 jQuery 有没有放在 static 的资料夹
<h1>DATA : API</h1>
<h2>API : GET</h2>
<button id='btnGet'>GET</button>
<hr>
<h2>API : POST</h2>
<p>APP_ID :
    <input id="app_id" name="app_id" type="number" />
</p>
<p>APP_NAME :
    <input id="app_name" name="app_name" type="text" />
</p>
<p>APP_VERSION :
    <input id="app_version" name="app_version" type="text" />
</p>
<p>APP_AUTHOR :
    <input id="app_author" name="app_author" type="text" />
<p>APP_REMARK :
    <input id="app_remark" name="app_remark" type="text" />
</p>
<button id="btnPost">POST</button>
<hr>
<h3>Console : </h3>
<div id="console"></div>
  • <button id='btnGet'>GET</button> : GET 按钮,用来触发 Ajax 访问取得资料的 API
  • <button id="btnPost">POST</button> : POST 按钮,用来将五项输入框的文字,透过 Ajax 传递给 API
    • <input id="app_id" name="app_id" type="number" />
    • <input id="app_name" name="app_name" type="text" />
    • <input id="app_version" name="app_version" type="text" />
    • <input id="app_author" name="app_author" type="text" />
    • <input id="app_remark" name="app_remark" type="text" />
  • <div id="console"></div> : Console 文字区块,用来打印 Ajax 接收的资料内容
var $btnGet = $('#btnGet');
var $console = $('#console');
var $btnPost = $('#btnPost');
var $edtAppId = $('#app_id');
var $edtAppName = $('#app_name');
var $edtAppVersion = $('#app_version');
var $edtAppAuthor = $('#app_author');
var $edtAppRemark = $('#app_remark');
  • 使用 jQuery 取得 Html 的画面元素
$btnGet.off('click').on('click', function () {
    $.ajax({
        url: '/data/message',
        data: {},
        type: 'GET',
        success: function (data) {
            $console.text("");
            $console.append("data[id] : " + data.appInfo.id + "---");
            $console.append("data[name] : " + data.appInfo.name + "---");
            $console.append("data[version] : " + data.appInfo.version + "---");
            $console.append("data[author] : " + data.appInfo.author + "---");
            $console.append("data[remark] : " + data.appInfo.remark + "---");

            $edtAppId.val(data.appInfo.id);
            $edtAppName.val(data.appInfo.name);
            $edtAppVersion.val(data.appInfo.version);
            $edtAppAuthor.val(data.appInfo.author);
            $edtAppRemark.val(data.appInfo.remark);
        },
        error: function (xhr) {
            alert('Ajax request 发生错误');
        }
    });
})
  • $btnGet.off('click').on('click', function () {}) : GET 按钮点击事件
  • $.ajax({}) : 使用 jQuery 的 Ajax 函式
    • url: '/data/message' : 访问路径为 /data/meesage
    • data: {} : 不传递资料
    • type : 'GET' : 使用 GET 方法
    • success: function (data) {} : 成功的话,触发函式动作
      • $console.text(""); + $console.append("...") : 将资料打印在 Console 元件上
      • $edtAppXXX.val(...); : 将数值内容填入到,画面上的五个输入框。
    • error: function (xhr) {} : 失败的话,触发函式动作
      • alert('Ajax request 发生错误'); : 显示对话视窗,Ajax request 发生错误
$btnPost.off('click').on('click',function(){
    $.ajax({
        url: '/data/message',
        data: {
            "app_id" : $edtAppId.val() , 
            "app_name" : $edtAppName.val(),
            "app_version" : $edtAppVersion.val(),
            "app_author" : $edtAppAuthor.val(),
            "app_remark" : $edtAppRemark.val(),
        },
        type: 'POST',
        success: function (data) {
            $console.text("result = ");
            $console.append(data.result);
        },
        error: function (xhr) {
            alert('Ajax request 发生错误');
        }
    });
});
  • $btnPost.off('click').on('click',function(){}) : POST 按钮点击事件
  • $.ajax({}) : 使用 jQuery 的 Ajax 函式
    • url: '/data/message' : 访问路径为 /data/meesage
    • data: { ... } : 传递五个输入框的文字内容
      • "app_id" : $edtAppId.val()
      • "app_name" : $edtAppName.val()
      • "app_version" : $edtAppVersion.val()
      • "app_author" : $edtAppAuthor.val()
      • "app_remark" : $edtAppRemark.val()
    • type : 'POST' : 使用 POST 方法
    • success: function (data) {} : 成功的话,触发函式动作
      • $console.text("result = "); + $console.append("...") : 将资料打印在 Console 元件上
    • error: function (xhr) {} : 失败的话,触发函式动作
      • alert('Ajax request 发生错误'); : 显示对话视窗,Ajax request 发生错误

get 按钮,点击後资料传输流程
004

post 按钮,点击後资料传输流程
005

写入的 input.json 资料内容与输入框文字相同
006


开发配置 - 外网访问与热部署

补充两个开发时,应该要知道的配置

  • 允许外部的访问
  • Debug 模式

允许外部的访问

先前的程序码,如果试着使用,除 127.0.0.1 或 localhost 以外的网址,

例如: 区域网路 192.168.2.12,浏览器会显示「无法连上这个网站」

008

Flask 预设配置 是不允许外部的访问

增加配置

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

在 main 方法的 app.run() 函式中,加上 0.0.0.0 的字串。

配置到产品的服务器中,客户端的电脑才能够连接上网站的服务器。


Debug 模式

先前的程序码中,任何的修改都必须要重新启动。(网页的程序码也是如此)

增加配置

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

在 main 方法的 app.run() 函式中,加上 debug = True 开启 Debug 模式。

程序码的任何修改,储存後就会立刻生效,省去许多服务器重新启动的时间。

009


完整的程序码

dev-config.py

import flask
app = flask.Flask(__name__)

@app.route("/")
@app.route("/hello")
def hello():
    return "Hello, World ~ !!! Text Text Text ~ !!!"

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

後续

第三章节 Ajax 资料交换,後端 Python 的实作是使用读写 json 的档案,来模拟资料持久化的部分。

不过真实的後端开发,都应该会使用关联式的资料库,例如 : MySQL、MS-SQL 来进行数据的保存。

这部分,不在 flask 的套件里面,必须安装 flask_sqlalchemy 与相对应的 python sql 套件,才能够进行实作。

007

後续会独立说明。


参考资料

Flask 官网

https://flask.palletsprojects.com/en/2.0.x/

Tutorialspoint - Flask

https://www.tutorialspoint.com/flask/index.htm


<<:  【Day3】声音的特徵提取

>>:  Day03. 进入No code/Low code 的世界- 安装 Blue Prism

IAP 建立Https

IAP Https 今天来说说IAP在连线网页上的实作以及运用,昨天已有大致的提到了IAP对应Htt...

设计模式种类与建议研读方法

在这本GOF的设计模式中 共有23种设计模式 作者将这些设计模式又依照目的性粗略分为三大类,分别是:...

[Day8] 从入门到入狱! 用Python窃听电脑键盘事件!

《刑法》第315之1条:「无故利用『工具』或『设备』窥视、窃听」或无故以『录音』、『照相』、『录影...

Reader 的 MockK 测试

Reader 是我们 Android library 里面最外层的 API ,要测试它要先考虑它有跟...

[Day04] 安装 IDE 与 .NET SDK

开发 .NET 程序之前,需要安装两个东西: IDE: 让我们编写程序与 debug .NET SD...