# Python Flask
資訊之芽 梁安哲 2022/05/15
---
## 大家好久不見
超級貓貓星際漫遊3 有解出來嗎
---
## 課程大綱
1. 基礎網路知識
2. Flask 基本架構
3. Routing 路由
4. Template 模板
5. Form 表單
6. Deploy 部屬
---
## 課程資料
下載: https://github.com/maowman/py-flask
順便複習上周的內容。
---
## 基礎網路知識
----
### 我們怎麼看到網頁的
----
![](https://i.imgur.com/Okt0EQz.jpg)
----
### 假設你今天想要訪問`http://www.example.com/`
![](https://i.imgur.com/K2Dvbds.png)
----
### DNS(Domain Name System)
![](https://i.imgur.com/HQLHChp.png)
----
### 利用 HTTP/HTTPS 請求網頁內容
![](https://i.imgur.com/PTiZgzk.png)
----
### 接收檔案
1. 程式檔 (Code files): HTML , CSS , Javascript , webassembly
2. 資產檔 (Asset): 圖片 , 影片 , 音樂 ...
![](https://i.imgur.com/srCExD0.png)
----
### 渲染頁面
![](https://i.imgur.com/XQGAszj.jpg)
----
### 那Python去哪裡了?
----
### 前端、後端?
前端是瀏覽器上運行的程式碼。由於瀏覽器上只能執行HTML、CSS、Javascript、webassembly,因此前端只以這四種語言構成。
後端是伺服器上運行的程式碼。基本上可以使用任何程式語言。
----
### Why 框架
1. 提供函式庫、應用程式架構
2. 易於維護、更新
3. 其他人也在用
----
### Which 框架
![](https://i.imgur.com/BLLOc5c.png)
[source](https://blog.back4app.com/backend-frameworks/)
---
## Flask 基本架構
----
### 前置作業
1. 安裝套件 `pip install flask`
2. 準備一個獨立的資料夾裝所有檔案
----
### Hello Sprout !
``` python=
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_sprout():
return "<h1>Hello, Sprout! My name is 超級貓貓男</h1>"
if __name__ == "__main__":
app.run()
```
----
### 初始化
``` python=
from flask import Flask
app = Flask(__name__)
```
----
### 建立路由(route)與頁面(view)
``` python=
@app.route("/")
def hello_sprout():
return "<h1>Hello, Sprout! My name is 超級貓貓男</h1>"
```
----
### 執行網路應用程式
```python=
if __name__ == "__main__":
app.run()
```
----
### 另外一個方法
1. 設定環境變數。
- Windows cmd: ```set FLASK_APP=sprout-1```
- Windows Powershell: ```$env:FLASK_APP = "sprout-1"```
- Mac/Linux: ```export FLASK_APP=sprout-1```
2. 執行```flask run```
----
![](https://i.imgur.com/hxoVg1e.png)
----
![](https://i.imgur.com/xKoKDRz.png)
----
### 現在是...練習時間
讓伺服器顯示自己的名字。
執行的時候使用```app.run(host="0.0.0.0")```。
----
### 補充說明
```
<h1>Hello, Sprout! My name is 超級貓貓男</h1>
```
這東西超怪對吧
----
### 看看資芽官網
```html=
<div id="back">
<img class="logo" src="/spt/index_bk1.png"></img>
<div id="nav">
<ul class="rside">
<li class="plan"><a href="javascript:reload_page('/spt/')">計劃</a></li>
<li class="about"><a href="javascript:reload_page('/spt/about/')">關於</a></li>
<li class="qa"><a href="javascript:reload_page('/spt/qa/')">Q&A</a></li>
</ul>
<ul class="lside">
<li class="rule"><a href="javascript:reload_page('/spt/rule/')">規則</a></li>
<li class="poll"><a href="javascript:reload_page('/spt/poll/')">評價</a></li>
<li class="indiv"><a href="javascript:reload_page('/spt/indiv/');">個人</a></li>
</ul>
</div>
<div class="foot">
<span>訊息公告暨粉絲專頁: <a href="https://www.facebook.com/ntucsiesprout"><u>資訊之芽培訓計畫</u></a></span><br>
<span>電子郵件地址: <a href="mailto:sprout@csie.ntu.edu.tw">sprout@csie.ntu.edu.tw</a></span><br>
<span></span><br>
</div>
</div>
<div id="main"></div>
<div id="overlay">
<img src="/spt/ring-alt.svg" id="loading"></img>
</div>
```
----
### HTML
![](https://i.imgur.com/HhX59e9.png)
ref: https://developer.mozilla.org/en-US/docs/Glossary/Element
因為我們是教Python,所以不會太深入講。有興趣的學員可以參考[這裡](https://www.w3schools.com/html/)。
---
## Routing 路由
----
![](https://i.imgur.com/TJoMHXn.png)
![](https://i.imgur.com/rL5DKtH.png)
![](https://i.imgur.com/5frAL59.png)
網站上可以有很多頁面(view),可以通過不同路由(route)存取
----
```python=
@app.route("/lecturer")
def lecturer():
return '<blockquote class="imgur-embed-pub" lang="en" data-id="a/5Hh8HRm" data-context="false" ><a href="//imgur.com/a/5Hh8HRm"></a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>'
@app.route("/price")
def fee():
return "<p>兩個階段都1700</p>"
```
----
### 動態路由
```python=
@app.route("/student/<studentName>")
def hello_student(studentName):
return f"<h1>Hello, {studentName}!</h1>"
```
----
### HTTP 協定
```python=
@app.route("/secret")
def getSecret():
try:
inputPassword = request.args.get("password")
if (password != inputPassword ):
raise Exception("Password incorrect")
return "<h1>我的房子還蠻大的</h1>"
except Exception as e:
return f"403 Forbidden : {e}" , 403
```
----
#### HTTP 有用的小知識
parameters
![](https://i.imgur.com/vU7pzy4.png)
----
status code
![](https://i.imgur.com/vAZH1qr.png)
----
### Redirect
```python=
@app.route("/rick")
def rickroll():
return redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
```
----
### 現在是...練習時間
做一個網站顯示造訪人次
---
## Template 模板
----
### 前置作業
1. 建立名為```templates```的資料夾放模板檔案(一字不差)
----
### 邏輯與頁面分離
```python=
@app.route("/")
def index():
return render_template("index.html")
```
```html=
<h1>Hello Sprout!</h1>
```
----
### Jinja2 模板引擎
動態渲染網頁內容
----
### 變數
```python=
@app.route("/jay")
def jaySayHi():
return render_template("jay.html" , longName = "阿傑" , shortName = "傑哥")
```
```html=
<h1>對了,我叫{{ longName }},我也常來這裡玩,痾,他們都叫我{{ shortName }}。</h1>
```
----
### 條件
```python=
@app.route("/adult")
def adult():
age = 0
try:
age = int( request.args.get("age"))
except Exception as e:
print(e)
return render_template("adult.html" , age = age )
```
```html=
<h1>都{{ age }}歲了還那麼害羞</h1>
{% if age > 18 %}
<h1>還可以教你登大人喔</h1>
{% else %}
<h1>但是你不能登大人。</h1>
{% endif %}
```
----
### 迴圈
```python=
@app.route("/store")
def store():
cart = {"酒":10 , "麵包":20 , "南瓜":887414}
return render_template("store.html" , cart = cart )
```
```html=
<h1>什麼都可以拿嗎杰哥?</h1>
{%for item , quantity in cart.items() %}
<p>{{item}} 買了 {{quantity}} 個。</p>
{% endfor %}
```
----
### 繼承
```html=
{% block title %}
<h1>國立臺灣大學</h1>
<p>
國立臺灣大學是一所積極新創、學科齊全、學術實力雄厚、辦學特色鮮明,在國際上具有重要影響力與競爭力的大學,在多個學術領域具有非常前瞻的科技實力,擁有世界一流的實驗室與師資力量,各種排名均位於全球前列。歡迎大家報考國立臺灣大學。
</p>
<a href="{{url_for("ntu")}}">返回主頁</a>
{% endblock %}
{% block content %}
{% endblock %}
```
----
```python=
@app.route("/ntu")
def ntu():
return render_template("ntu.html")
```
```html=
{% extends "ntuBase.html" %}
{% block title %}
{{super()}}
<style>
h1{
color: red;
}
</style>
{% endblock %}
{% block content %}
<p>國立臺灣大學前身為日治時期之「臺北帝國大學」(創立於日本昭和3年、西元1928年、民國17年)。當時首任校長為幣原坦總長;至民國34年(1945年)二次世界大戰結束,日本投降、臺灣光復,同年11月15日我政府完成接收臺北帝國大學,改制更名為「國立臺灣大學」,由羅宗洛博士任首任校長。</p>
{% endblock %}
```
----
安裝套件```pip install xlrd```
```python=
@app.route("/ntu/<departmentCode>")
def department(departmentCode):
workbook = xlrd.open_workbook_xls("dpt_code.xls")
worksheet = workbook[0]
info = f"{departmentCode} 沒有這個科系"
for row , code in enumerate(worksheet.col(1)):
if (code.value == departmentCode):
info = f"{departmentCode}-{worksheet.cell_value(row , 2)} {worksheet.cell_value(row , 6)}"
return render_template("department.html" , info = info)
```
```html=
{% extends "ntuBase.html" %}
{% block title %}
{{super()}}
{% endblock %}
{% block content %}
<p>{{info}}</p>
{% endblock %}
```
----
### 現在是...練習時間
嘗試利用前面的內容,製作一個高中學校代碼查詢系統。
可以參考```99hscode.xls```。
---
## Form 表單
----
### 前置作業
1. 安裝套件 `pip install flask-wtf`
----
### 我們可能需要什麼?
資料雙向的流通
----
### HTTP method
1. GET 從伺服器拿資料。
2. POST 把資料給伺服器。
----
### Form
```python=
from flask_wtf import FlaskForm
from wtforms import StringField , SubmitField , IntegerField
from wtforms.validators import DataRequired
class rollcallForm(FlaskForm):
name = StringField("你的名字:" , validators=[DataRequired()])
email = StringField("你的電子信箱:" , validators=[DataRequired()])
studentId = IntegerField("你的學號:" , validators=[DataRequired()])
message = StringField("其他建議:")
submit = SubmitField("送出")
```
----
```html=
<h2>資訊之芽簽到表單</h2>
<h1>Hello {{name}}!</h1>
<form method="POST">
{{ form.hidden_tag() }}
<div>
{{form.name.label}} {{form.name()}}
</div>
<div>
{{form.email.label}} {{form.email()}}
</div>
<div>
{{form.studentId.label}} {{form.studentId()}}
</div>
<div>
{{form.message.label}} {{form.message()}}
</div>
<div>
{{form.submit()}}
</div>
</form>
```
----
### Session & Flash
```python=
@app.route("/", methods=["GET", "POST"])
def index():
if session.get("name") is None:
flash("歡迎來到資訊之芽!")
session["name"] = "資芽新學員"
form = rollcallForm()
if form.validate_on_submit():
session["name"] = form.name.data
print(form.data)
return redirect(url_for("index"))
return render_template("sproutForm.html", form=form, name=session.get("name"))
@app.route("/clear")
def clear():
session.clear()
return redirect(url_for("index"))
```
```html=
<a href="{{url_for("clear")}}">清除Session</a>
```
----
### 現在是...練習時間
用一個頁面顯示同一個學員在同一個 Session 的簽到記錄
---
## Deploy 部屬
----
### 試試看用不同的電腦連接到自己的網站
----
### pythonanywhere
![](https://i.imgur.com/iqGyT06.png)
----
![](https://i.imgur.com/g9wXsje.png)
----
![](https://i.imgur.com/HzF5y6w.png)
----
![](https://i.imgur.com/AQnSE3D.png)
----
![](https://i.imgur.com/msNFeI4.png)
----
![](https://i.imgur.com/HN0balx.png)
----
![](https://i.imgur.com/fZjETHM.png)
----
![](https://i.imgur.com/axuUv2u.png)
----
![](https://i.imgur.com/OmMJ0SN.png)
----
![](https://i.imgur.com/c4TIvYG.png)
網頁非常好
----
### 參考事項
1. https://help.pythonanywhere.com/pages/Flask/
---
## The sky is the limit
出於時間因素考量,只能很粗淺的介紹。
可以試著自己從頭到尾設計一個網路應用程式。
----
### 延伸學習資料
1. SQL資料庫 https://flask-sqlalchemy.palletsprojects.com/en/2.x/
2. Email發送 https://pythonhosted.org/Flask-Mail/
3. 一堆酷東西 https://www.fullstackpython.com/flask-extensions-plug-ins-related-libraries.html
4. 編教材時用的工具書 https://www.books.com.tw/products/0010793455?sloc=main
---
# 謝謝大家
{"metaMigratedAt":"2023-06-17T00:27:09.055Z","metaMigratedFrom":"Content","title":"Python Flask","breaks":true,"contributors":"[{\"id\":\"9714f580-8aea-4592-8613-b6e594740378\",\"add\":11637,\"del\":1672}]"}