Flask
輕量級 Web 應用框架
入門入不了土
《建北電資 2026 聯合寒訓》
1 簡介 + 環境
2 前端
HTML, Jinja2, CSS
3 後端
SQLalchemy
5 實作
4 前後端互動
WTForms
講師 Suzy (蘇西)


- 北資一六 學術長
- 2026 寒訓課程組組長
技能點:
- Python
- 機器學習 一點點 🤏
- C++ 可以說是會跟不會差不多
- 養了一隻 Labubu

成發問題可以標我
寶寶蘇西
心平氣和的蘇西
touching grass
hello
1 簡介
What is Flask

Flask 是一個使用 Python 語言開發的輕量級 Web 應用框架。近年來因為Python簡單易學的語法以及強大的生態系統,所以在Web開發領域也逐漸受到青睞。
- 基本功能簡單但擴充性強
- 自由度高
P.S. 據說它是一個裝酒的容器



常見 Python Web 框架
全棧框架 Full-stack
微框架 Micro-framework
現代化微框架 API-centric
內建強大的 Django ORM
需搭配 SQLalchemy 等數據庫
完整但較難上手
新手友善
效能高
Setup
1. 打開 VScode
2. 建立一個資料夾
pip install Flask3. 建一個 python 檔案(ex: app.py)
4.
Hello World
from flask import Flask
app = Flask(__name__) #建立一個應用 (app)
@app.route('/') #'/' 是「根路徑」,定義主頁要顯示的內容
def hello():
return ("Hello, World!")
if __name__ == '__main__':
app.run()
- Flask 會預設在 port 5000
- 執行
python app.py後,在瀏覽器輸入 localhost:5000 應該就可以看到你的網頁了。
Hello World
if __name__ == "__main__":
app.run(debug=True, port=5001)
debug 是指,當程式碼被更動並儲存後,網頁會自動更新。
Hello World
@app.route("/hello/<string:username>")
def hello(username):
return f"Hello, {username}!"可以透過 { } 插入特定值。(Jinja 語法,見後面介紹)
例如:localhost:5001/hello/suzy 就會輸出 “Hello, suzy!"
* 注意紙本講義勘誤
小實作 1
寫個東西然後成功的把它放到 localhost 上面
2 前端
@app.route('/')
def text():
return '
<html>
<body><h1>Hello World</h1></body>
</html>'
其實直接把 HTML 寫在 app.py 裡是可以的
但是當網頁比較複雜的時候
把 HTML 寫到另一個檔案可能比較合適
資料夾/
├── app.py
└── templates/
└── index.html
在原本的資料夾下面創建一個 templates 資料夾
然後把 HTML 檔案放進去
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ = "__main__":
app.run(debug=True)
render_template 會自己去 templates 資料夾找到 html 並載入
Jinja 2: HTML 模板化
Flask 內建的模板引擎是 Jinja2。
它的主要功用是將 HTML 與 來自 Python 的資料結合,生成最終的文本檔案。
Jinja 2: HTML 模板化
若是網頁有很多地方都要寫 HTML 的話,我們可以用Jinja 寫一個基礎模板 (template) ,每次需要寫一個 HTML檔案時,就可以直接匯入模板,再按照需求更動裡面的部分內容即可,不用從頭開始寫。
Jinja 2 語法 - 流程控制
{% if sunny %}
<p> 今天天氣晴 </p>
{% else %}
<p> 天氣不好 </p>
{% endif %}{% if 條件 %}
{% elif 條件 %}
{% else %}
{% endif %}
*勘誤:紙本講義上的程式碼漏掉 {% endif % }
@app.route('/')
def hello(sunny = True):
return render_template('index.html')index.html
app.py
Jinja 2 語法 - 迴圈
<h3>my list:</h3>
<ul>
{% for fruit in fruits %}
<li>{{ fruit }}</li>
{% endfor %}
</ul>
{% for x in list %}
{{x}}
{% endfor %}
@app.route('/')
def show_fruits():
# python list
fruit_list = ['蘋果', '香蕉', '西瓜', '草莓']
return render_template('index.html', fruits=fruit_list)
index.html
app.py
Jinja 2 - HTML 模板
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %} {% endblock %}
</head>
<body>
{% block body %} {% endblock %}
</body>
</html>
template.html
{% extends 'template.html' %}
{% block head %}
<title>這是標題</title>
{% endblock %}
{% block body %}
<h1>哈囉世界</h1>
{% endblock %}
引用 template.html
CSS
讓網站好看一點
推薦的檔案路徑如下
資料夾/
├── app.py
└── templates/
└── index.html
└── static/
└── main.css
我也不會寫 CSS
CSS 實作沒想法的可以參考講義、網路上的模板或問AI
url_for
這裡介紹一個 Flask 裡面的 函式 url_for
- 功能:透過函數名稱來反向找出對應的網址路徑
- 經常搭配 redirect 使用
- 優點:若更改路徑名稱,只要函式名稱沒有變,Flask 就還是可以幫你抓到正確的函式
from flask import Flask, render_template, redirect, url_for
# 記得 import
@app.route('/admin')
def admin():
# 如果沒權限,就把使用者踢回首頁
return redirect(url_for('home'))
url_for
我們可以用這個方法連到 CSS 檔案
- 功能:透過函數名稱來反向找出對應的網址路徑
- 經常搭配 redirect 使用
- 優點:若更改路徑名稱,只要函式名稱沒有變,Flask 就還是可以幫你抓到正確的函式
<link rel="stylesheet" href="{{url_for('static',filename='main.css')}}"
或者你也可以寫成這樣啦
<link rel="stylesheet" href="/static/main.css">
for 會寫 JS 的人:
載入 .js 檔案的方式是差不多的
<button id="Btn"> Click </button>
<script src="{{ url_for('static', filename='main.js') }}"></script>小實作 2
讓你的網站上包含 >= 2 個頁面
並加入 CSS 模板
3 後端

前端(Front-end)與後端(Back-end)是網站與應用程式開發的兩大核心層次。
前端專注於用戶可見的畫面、互動與視覺呈現,主要技術為 HTML、CSS、JavaScript。
後端則負責背後的運算邏輯、資料庫管理與伺服器運作,如 API 開發與資料處理。
簡言之,若網站要儲存大量資料或運算,我們大概還是需要個後端。
SQL (Structured Query Language)
SQL(Structured Query Language,結構化查詢語言)是一種專門用來管理、操作及查詢「關聯式資料庫」的標準程式語言。
OOP (Object Oriented Programming)
物件導向程式設計
ORM (Object-Relational Mapping)
物件關係映射
將資料庫中的「表格」映射為 Python 中的「類別(Class)」,將「資料列」映射為「物件(Instance)」。這樣一來,開發者可以用操作 Python 物件的方式來操作資料庫,而不需要寫原生的 SQL 語句
ORM 通常也有內建防止 SQL Injection (注入) 的機制,安全性高。
ORM (Object-Relational Mapping)
物件關係映射

圖片 from Google
SQLAlchemy
SQLAlchemy 是一款 Python Library,用於與關聯式資料庫進行互動。
- 用 Python 語法撰寫 SQL Query,與資料庫進行互動。
- 將 Python 物件映射到資料庫的 Table。可以直接用 OOP 的方式操作資料庫,無需直接使用 SQL 語言
SQLAlchemy
pip install flask-sqlalchemy
*注意:紙本講義上這裡好像有出錯

this is alchemy
在終端機輸入
from flask_sqlalchemy import SQLAlchemy
app.py 上面加上
SQLiteViewer

Vscode 可以裝這個擴充
(在Vscode 視窗左邊工具欄找到

然後搜尋)
URI (Uniform Resource Identifier)
統一資源識別碼

有點像是「地址」,用來識別某個唯一的資源
常見的 URL 其實是 URI 的一種
初始化資料庫
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///items.db'
#代表在目前專案的目錄下建立一個名為 items.db 的檔案。
#URI = universal resource identifier
db = SQLAlchemy(app) # 建立 db 物件
建立資料庫
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(length=30), nullable=False, unique=True )
description = db.Column(db.String(length=100), nullable=False)
# primary_key -> 用來定義每筆資料的 id
# length -> 該欄位長度上限
# nullable = False -> 該欄位不能留空
# unique = True -> 不同筆資料間該欄位的內容不能重複(例如:name 必須是獨一無二的)
建立資料庫
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(length=30), nullable=False, unique=True )
description = db.Column(db.String(length=100), nullable=False)
def __repr__(self):
return f"Item('{self.id}', '{self.username}', '{self.description}')"
# 注意這個函式是寫在 Class 裡面
# 疑似紙本講義這裡有錯,自己注意一下(?)如何手動建立一筆資料
flask shell在終端機輸入
from app import db
db.create_all()
from app import User
接著可以打
如何手動建立一筆資料
person1 = User(username = "小明", description = "一個人")
db.session.add(person1)
db.session.commit()
建立一筆資料的步驟
小實作 3
建立一個資料庫
並試著登入幾筆資料
4 前後端互動
如果要讓網站使用者輸入的資料可以登記到後端
要怎麼做
Cookies
Cookies 是伺服器傳送給瀏覽器的一小段文字資料。瀏覽器會把它存在用戶的瀏覽器(客戶端),並在下次你訪問同一個網站時,自動把這段資料帶回給伺服器。


講師選圖選很久噢

Sessions
由於 Cookies 存在用戶端不安全(容易被偽造),我們通常將敏感資料(如:User ID、購物車內容)存放在伺服器的 Session 中。
簡化過後,Session 的運作原理:
- 伺服器在後端開一個 Session,裡面放你的資料
- 伺服器只給瀏覽器一個 Session ID,並存放在 Cookie 中。
- 下次你來訪時,帶著 Session ID,伺服器就能找到你的個人資料。


圖片 by Google
WTForms (What the Forms)
WTForms是一個 Python 的函式庫,它提供了Python開發者在開發網站時,需要的表單呈現以及表單的驗證等功能。
pip install WTFormsForms 的各種物件介紹
Forms表單是 WTForms 最主要的核心容器。Forms表單是Fields欄位的集合,可以選擇透過 python 字典dictionary來蒐集Forms的內容。
小知識— Python dictionary (字典) 語法
d = {key1: value1, key2: value2}就是 key 跟 數值的配對而已啦
Forms 的各種物件介紹
- 每個
Fields欄位都代表某一種資料的類型,且Fields欄位限制使用者僅能夠輸入符合該資料類型的數據。e.g.,IntegerField與StringField
- 為了提供各種驗證規則,
Fields欄位包含了一系列的驗證方式。
初始化 Form
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
app.config['SECRET_KEY']='mykey'
# 這邊先隨便設了一個 key
if __name__ == '__main__':
app.run(debug = True)
*注意:理論上應該要把 key 放在 .env 裡面,像這樣寫
import os
SECRET_KEY = os.getenv('SECRET_KEY')
app = Flask(__name__)
app.config['SECRET_KEY'] = SECRET_KEYSECRET_KEY = '某個亂碼'.env
app.py
建立一個 Form
class MyForm(FlaskForm):
name = StringField('你的名字', validators=[DataRequired()])
hobby = SelectField('你的興趣', choices=[('coding','打扣'),('gaming','遊戲'),('novels','小說')])
others= TextAreaField()
submit = SubmitField("確認")建立 route
@app.route('/',methods=['GET','POST'])
def index():
form = MyForm()
if form.validate_on_submit():
session['name'] = form.name.data
session['hobby'] = form.hobby.data
session['others'] = form.others.data
return redirect(url_for('thankyou'))
return render_template('home.html', form=form)
@app.route('/thankyou')
def thankyou():
"""thankyou頁"""
return render_template('thankyou.html')
表單頁面
{% block content %}
<div class="container">
<form method="POST">
{{form.hidden_tag()}}
{{form.name.label(class='form-label')}}
{{form.name(class='form-control')}}
<br>
{{form.hobby.label(class='form-label')}}
{{form.hobby(class='form-control')}}
<br>
{{form.others.label(class='form-label')}}
{{form.others(class='form-control')}}
<br>
{{form.submit(class='btn btn-primary')}}
</form>
</div>
{% endblock %}
home.html
thankyou.html 之類的就自己寫喔
完整程式碼
成發請不要直接抄它 </3
資料夾/
├── app.py
├── .env
├── static/
│ └── style.css
└── templates/
├── home.html
└── thankyou.htmlfrom flask import Flask, render_template, redirect, url_for, session
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SelectField, SubmitField
from wtforms.validators import DataRequired
from dotenv import load_dotenv
import os
load_dotenv()
SECRET_KEY = os.getenv('SECRET_KEY')
app = Flask(__name__)
app.config['SECRET_KEY'] = SECRET_KEY
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///items.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(length=30), nullable=False)
hobby = db.Column(db.String(length=30), nullable=False)
others = db.Column(db.String(length=100), nullable=False)
def __repr__(self):
return f"User('{self.name}', '{self.hobby}')"
class MyForm(FlaskForm):
name = StringField('你的名字', validators=[DataRequired()])
hobby = SelectField('你的興趣', choices=[('coding','打扣'),('gaming','遊戲'),('novels','小說')])
others = StringField('想說的話', validators=[DataRequired()])
submit = SubmitField('送出')
@app.route('/', methods=['GET', 'POST'])
def index():
form = MyForm()
if form.validate_on_submit():
new_user = User(
name=form.name.data,
hobby=form.hobby.data,
others=form.others.data
)
db.session.add(new_user)
db.session.commit()
session['name'] = form.name.data
return redirect(url_for('thankyou'))
return render_template('home.html', form=form)
@app.route('/thankyou')
def thankyou():
name = session.get('name', ' ')
return render_template('thankyou.html', name=name)
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(debug=True, port=5001)app.py
body {
font-family: "Courier New", Courier, monospace;
background-color: #ffffff;
display: flex;
justify-content: center;
padding-top: 50px;
color: #000000;
}
.form-container {
background: #ffffff;
padding: 2rem;
border: 2px solid #000000;
width: 100%;
max-width: 400px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
text-transform: uppercase;
font-size: 0.8rem;
letter-spacing: 1px;
}
input, select {
width: 100%;
padding: 10px;
border: 1px solid #000000;
border-radius: 0;
box-sizing: border-box;
outline: none;
}
input:focus {
background-color: #f0f0f0;
}
.btn-submit {
background-color: #000000;
color: #ffffff;
border: 1px solid #000000;
padding: 12px;
border-radius: 0;
cursor: pointer;
width: 100%;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
transition: all 0.2s ease;
}
.btn-submit:hover {
background-color: #ffffff;
color: #000000;
}style.css
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="form-container">
<h2>請填寫資訊</h2>
<form method="POST">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.name.label }}
{{ form.name() }}
</div>
<div class="form-group">
{{ form.hobby.label }}
{{ form.hobby() }}
</div>
<div class="form-group">
{{ form.others.label }}
{{ form.others() }}
</div>
{{ form.submit(class='btn-submit') }}
</form>
</div>
</body>
</html>home.html
SECRET_KEY = 'asdfghjkl123456789' #某個亂碼.env
5 成發
以小隊為單位
React 和 Flask 請(至少)擇一做成發
Flask 成發要求:要有前後端,但題材不限
亦可以結合其他的課程 ex: 機器學習
model = keras.models.load_model('mlp.keras')
(Google Colab)

用 Flask 部署模型 喜獲網站
謝謝大家
祝成發順利
Flask: 寒訓
By Suzy Huang
Flask: 寒訓
- 45