歐對 我打字很快算學術力嗎 :P
是什麼可以吃嗎?
就是在伺服器處理前端不能處理的東西
例如:密碼登入之類的東西
沒有後端的網站 -> 靜態網站
有後端的網站 -> 動態網站
處理後端的程式語言有非常多種:
像是 php, javascript, python 之類的
而我們今天要教的是python的Flask函式庫,專門來處理網頁後端的
下載
(就看你現在這台電腦有沒有載吧)
1. 下載python:網站
2. 在vscode確認有沒有選對的版本:
1. 先在vscode建立一個簡單的前端網站
(我相信你們昨天才學過 還記得怎麼作)
2. 下載vscode的python extension
3. 下載Flask package
pip install Flask開啟terminal
打入這個指令
那要怎麼從一個檔案走到另一個檔案呢?
(讓html知道我們的檔案在哪裡)
假設我們要從index.html走到funny.png:
一些要知道的小知識:
"." - 現在這個資料夾
"/" - 要走的途徑
".." - 返回上一層資料夾
所以就會是:(拿昨天學得的前端來當例子)
<link href="./images/funny.png" rel="icon">4. 建立一個python檔案 (.py)
5. 檔案結構(Flask才能運作)
html 放 ./templates
css 放 ./static/css
js 放 ./static/js
圖片放 ./static/images
基礎語法
(這裡預設你已經有學過一些程式語言)
a = 10 #整數
b = 20.2 #小數
c = 'string' #字串
d = [10, 30, 40] #陣列
# 對不需用跟他說是什麼類型a = 10
b = 20
if a == 15:
print("a is 15")
elif b == 20:
print("b is 20")
else:
print("neither is true")
#對 python 不用小括號
#對 python 不用分號
#對 python 不用大括號 (不下放btw)a = 10
while a < 20:
print(a)
a += 1
# 應該蠻直觀的# 重複10次
for i in range(10): #i 會是 0~9
print(i)
for i in range (2, 19, 2): #如果翻譯成c++或js就會是 for (int i=2; i<19; i+=2)
print(i)
arr = ["apple", "banana", "tomato"]
for i in arr: #i 會是 arr 中的元素
print(i)
def add(a, b):
ans = a+b
return ans
print(add(1, 2))
#python宣告函式的方法是def
#剩下就和其他語言差不多了fruit = "apple"
print(f'My favorite fruit is {fruit}')
#可以在字串中加入變數 很好用語法
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
if __name__ == '__main__':
app.run(debug=True,port=5000)除了3-5行之外
大致上都是複製貼上 可以先不用理解
(只要知道他導入Flask
然後可以讓網站跑就好了)
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
if __name__ == '__main__':
app.run(debug=True,port=5000)@app.route("/a")
def helloa():
return "Hello, World! aaa"這個函式跑得網站:
http://127.0.0.1:5000/a
from flask import render_template
@app.route("/a")
def hellob():
name = "John"
return render_template("index.html", name=name)<h1>Hello {{ name }}!</h1>html檔案 (等一下會介紹 不急)
@app.route('/add/<int:a>/<int:b>')
def add(a, b):
return f'{a} + {b} = {a+b}'http://127.0.0.1:8080/add/3/4
如何將使用者導入其他網址
from flask import redirect, url_for
@app.route("/")
def main():
return redirect(url_for("other_route"))
#將使用者導到 /other_route 這個網址/random/<int:min>/<int:max>
這個路由會在 min 和 max 之間產生一個隨機數並回傳,例如:
/random/1/100 → 隨機數:67
import random
使用 random.randint(min, max)
from flask import Flask
import random
app = Flask(__name__)
@app.route('/random/<int:a>/<int:b>')
def main(a, b):
return f'random number is {random.randint(a, b)}'
if __name__ == '__main__':
app.run(debug=True,port=5000){{ 兩個大括號是變數 }}
{% 執行jinja2內置函數 %}
{# 註解說明 #}from flask import render_template
name = "World"
return render_template("index.html", name=name)from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route("/")
def hello():
name = "World"
return render_template("index.html", name=name)
if __name__ == '__main__':
app.run(debug=True,port=5000)<h1>Hello {{ name }}!</h1>from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route("/")
def main():
name = "admin"
return render_template("index.html", name=name)
if __name__ == '__main__':
app.run(debug=True,port=5000) {% if name == "admin" %}
<h1>Logged in, Hello {{ name }}!</h1>
{% else %}
<h1>Not Logged in, Try again!</h1>
{%endif%}from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route("/")
def main():
items = ["apples", "bananas", "tomatoes"]
return render_template("index.html", items=items)
if __name__ == '__main__':
app.run(debug=True,port=5000) {% for item in items %}
<li> {{ item }} </li>
{% endfor %}如何在html導入css, js
(可以直接用url_for)
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/main.js') }}"></script>from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route("/")
def main():
arr = [1, 2, 5, 7, 3, 8, 10]
return render_template(("index.html"), arr = arr)
if __name__ == '__main__':
app.run(debug=True,port=5000) {% for i in arr %}
{% if i%2 == 0 %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}假設今天我們要把一個東西從前端傳到後端
那我們要怎麼達到呢?
(沒是我只是想秀我setup和btr的東西)
資訊(如我空格輸入的東西)
他要這個資訊
| 方法 | get | post |
|---|---|---|
| 如何 | 直接加在URL後 head |
傳送資料另外寫 body |
| 好處 | 便宜 | 安全 |
| 壞處 | 不安全 | 貴 |
| 屬性 | request.args | request.form |
沒有哪個一定比較好 要看情況
http://127.0.0.1:5000/get_example?name=ming&email=ming@example.com
http://127.0.0.1:5000/get_example/ming/ming@example.com
都可以取得兩個資訊
那兩個有什麼區別呢?
| Query String (?a=5&b=10) | Path Variables (/5/10) | |
|---|---|---|
| 傳遞方式 | request.args.get() | <int:a>、<int:b> |
| 適合場景 | 搜尋、可選參數 | 固定結構的 API |
| URL 範例 | /add?a=5&b=10 | /add/5/10 |
| 可選參數 | 可以省略(使用 default) | 不能省略,必須填值 |
| 可讀性 | 較靈活,適合不固定的查詢 | 較清楚,適合固定格式 |
(你們昨天應該有學到table吧)
<h2>get method:</h2>
<form action="/get_example" method="get">
<table border="1">
<tr>
<th>欄位</th>
<th>輸入</th>
</tr>
<tr>
<td>姓名</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>電子郵件</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="送出"></td>
</tr>
</table>
</form>
後端找的內容
跟表單說這是get
(你們昨天應該有學到table吧)
<h2>post method</h2>
<form action="/post_example" method="post">
<table border="1">
<tr>
<th>欄位</th>
<th>輸入</th>
</tr>
<tr>
<td>使用者名稱</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密碼</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"></td>
</tr>
</table>
</form>
後端找的內容
跟表單說這是post
from flask import Flask
from flask import redirect
from flask import request, render_template
app = Flask(__name__)
@app.route("/")
def main():
return render_template("index.html")
@app.route("/get_example", methods=['GET']) #form把資訊傳到 "/get_example", 我們和flask說這是get method
def get_example():
if request.args:
#取得我們form的資料(在URL中)
name = request.args.get('name')
email = request.args.get('email')
return f'<h2>{name} / {email} </h2>'
else:
return redirect("http://127.0.0.1:5000/") #如果沒收到,就回到主畫面
if __name__ == '__main__':
app.run(debug=True,port=5000)from flask import Flask
from flask import redirect
from flask import request, render_template
app = Flask(__name__)
@app.route("/")
def main():
return render_template("index.html")
@app.route("/post_example", methods=['GET', 'POST']) #form把資訊傳到 "/post_example", 我們和flask說這是post method
def post_example():
if request.method == 'POST':
#取得我們form的資料
name = request.form['username']
email = request.form['password']
return f'<h2>{name} / {email} </h2>'
else:
return redirect("http://127.0.0.1:5000/") #如果沒收到,就回到主畫面
if __name__ == '__main__':
app.run(debug=True,port=5000)http://127.0.0.1:5000/a
http://127.0.0.1:5000/b
| Cookie | Session | |
|---|---|---|
| 存在哪裡? | 使用者 (Client 端) |
伺服器 (Server 端) |
| 安全性 |
不安全 容易被竊取、修改 |
安全 因為存放在伺服器 |
| 適用情境 | 記住登入狀態、偏好設定 (較不重要的東西) |
會員登入、銀行交易 (需要更高安全性) |
from flask import Flask, session
app = Flask(__name__)
secret_key = 'c4dffa417abe4d31936cdf52d3a6d7ae'
app.config['SECRET_KEY'] = secret_key #用來加密的
#有一個 session 的 dict,可以儲存一個使用者的資訊,並且在route之間溝通
@app.route('/login')
def login():
session['login'] = True
return 'Login success'
@app.route('/logout')
def logout():
session['login'] = False
return 'Logout success'
@app.route('/main')
def profile():
if session.get('login'): #login
return 'Main page'
else: #not login
return 'User not logged in'
if __name__ == '__main__':
app.run(debug=True, port=5000)# 生成一個隨機的 secret key
import uuid
print(uuid.uuid4().hex)建立一個前端能輸入 使用者名稱跟密碼
他打什麼使用者名稱就把他存到 session 裡
並且做出一個admin介面
只有使用者名稱為admin和密碼符合才可查看
簡單來說就是建立一個簡單的登入頁面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>post method</h2>
<form action="/post_example" method="post">
<table border="1">
<tr>
<th>欄位</th>
<th>輸入</th>
</tr>
<tr>
<td>使用者名稱</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密碼</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>from flask import Flask
from flask import redirect
from flask import request, render_template, url_for, session
app = Flask(__name__)
secret_key = 'c4dffa417abe4d31936cdf52d3a6d7ae'
app.config['SECRET_KEY'] = secret_key #用來加密的
@app.route("/")
def main():
return render_template("index.html")
@app.route("/post_example", methods=['GET', 'POST']) #form把資訊傳到 "/post_example", 我們和flask說這是post method
def post_example():
if request.method == 'POST':
#取得我們form的資料
#把我們input的資料存到session
session['name'] = request.form['username']
session['password'] = request.form['password']
#判斷我們的輸入是否正確
if session['name'] == 'admin' and session['password'] == 'admin':
return redirect(url_for('success'))
else:
return redirect(url_for('fail'))
else:
return redirect("http://127.0.0.1:5000/") #如果沒收到,就回到主畫面
@app.route("/success")
def success():
#這裡用session,表示可以在路由之間傳送資訊
return f"success! your name is {session['name']}, and your password is {session['password']}"
@app.route("/fail")
def fail():
return f"login failed, please try again"
if __name__ == '__main__':
app.run(debug=True,port=5000)一定要一模一樣
(對他是沒有名字的檔案 然後副檔名是 .env)
pip install python-dotenv變數 = 值
變數 = "字串"secret_code = 67
password = "password"1. 創建 .gitignore 檔 (對名字要一模一樣)
from flask import Flask
import os
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
@app.route("/")
def main():
pw = os.getenv("password")
return f'password is: {pw}'
if __name__ == '__main__':
app.run(debug=True,port=5000)password = "password"
(例如可以存存看剛剛的secret_key)
假設我們要從前端取後端的資訊,或是從其他伺服器拿資訊的化,我們要怎麼作呢?
(對我用了同張圖)
前端 (or 後端)
後端 (or 其他伺服器)
簡單來說,我們可以用api,從其他伺服器(或自己的)拿取資料
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/api_get', methods=['GET'])
def api_get():
name = request.args.get('name')
email = 'placeholder' #(可以從name拿一些資訊 啊我懶得做了 你們可以自己想想看)
return jsonify({'message': f'Hello, {name}! Your Email is {email}.'})
@app.route('/')
def home():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True, port=5000)<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flask Class</title>
</head>
<body>
<!--這裡可以有些輸入,像是要傳給後端的資料-->
<input id="name">
<button onclick="send_get_request()">click to get information!</button>
<p id="response"></p>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
</html>function send_get_request(){
//避免特殊字元(像是空格、&、=、/ 等)破壞網址格式。
let name = document.getElementById("name").value;
//encodeURIComponent() 是用來對使用者輸入的做 URL 編碼
fetch(`/api_get?name=${encodeURIComponent(name)}`)
.then(res => res.json()) //回應為 JSON
.then(data => document.getElementById("response").innerText = data.message) //把那個資訊(data) 變成 #response 的文字
.catch(err => console.error("錯誤:", err)); //如果錯誤的話
}建立一個和剛剛類似,可以從前端輸入名字,
然後取得一些使用者資料的網站
(答案在上面,我懶得在用了 :P)
在python 取得其他api的資訊
舉例來說:discord的api
每個api 通常來說都有 docs,
他會跟你說要輸入什麼,然後他會回傳什麼
舉例來說:用discord bot取得使用者資訊
import requests
API_ENDPOINT = "https://discord.com/api/v10"
def exchange_code(code):
# gets the access_token
data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': redir
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post(f'{API_ENDPOINT}/oauth2/token', data=data, headers=headers, auth=(client_id, client_secret))
r.raise_for_status()
return get_user_data(r.json()['access_token'])
def get_user_data(accessToken):
# gets the user id from the access_token
headers = {
"Authorization": f"Bearer {accessToken}"
}
r = requests.get(url=api_url, headers=headers)
r.raise_for_status()
return r.json()
這兩個是dc bot的資訊
我們從這個api的網址request資訊
(開不懂沒關係 通常這種東西都用抄的)
Data Base
websocket
blueprint