# Flask 教學 ---- Flask 是個輕量級的程式語言,其簡單的程式碼就可以架構出一個簡易的http服務應用。 ---- ## 簡易用 Flask 架設的網站 ```python= from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' if __name__ == '__main__': app.debug = True app.run() ``` ---- ### 說明各部份參數 --- # 路由 & 參數 一個網站裏面,會有各式各樣的路徑,而這些路徑,在網站裏面稱作路由,會決定哪個網址由哪段程式碼處理 ---- ```python= @app.route('/') def index(): return 'Index Page' @app.route('/hello') def hello(): return 'Hello, World' ``` ---- 除了這些靜態路由,當然還有所謂的動態路由 ```python= @app.route('/user/<username>') def show_user_profile(username): # show the user profile for that user return 'User {}'.format(escape(username)) @app.route('/post/<int:post_id>') def show_post(post_id): # show the post with the given id, the id is an integer return 'Post {}'.format(post_id) ``` ---- 目前支援以下的參數 | type | 說明 | | ------:|:---------------------------------------:| | string | (default) 除了 `/` 的任意字元組成的字串 | | int | 正整數 | | float | 正浮點數 | | path | string + `/` | | uuid | UUID 字串 | --- # Templates Flask 預設使用 [JinJa2](https://jinja.palletsprojects.com/en/2.11.x/templates/) 模板排版引擎 ---- ```python= from flask import render_template @app.route('/hello/') @app.route('/hello/<name>') def hello(name=None): return render_template('hello.html', name=name) ``` ---- 模板要放在 templates 的資料夾內 ``` /application.py /templates /hello.html ``` ---- 以下是一個簡易模板的內容 ```htmlmixed= <!doctype html> <title>Hello from Flask</title> {% if name %} <h1>Hello {{ name }}!</h1> {% else %} <h1>Hello, World!</h1> {% endif %} ``` ---- 使用 Flask + Jinja2時,在模板內你可以存取 `request`, `session` and `g objects` ---- Flask 允許通過 function 去獲得網址,這點可以讓網址產生是動態的,在網頁裡可以顯示出該段的網址 --- # Method ## Get/Post/Put/Patch/Delete ---- 一般網頁只能使用 Get/Post Put/Patch/Delete 需要使用 JavaScript 來輔助 ---- ```python= @app.route('/method', methods=['POST', 'GET']) def method(): method = request.method data = request.form return render_template('method.html', method=method, data=data) ``` ---- method.html ```htmlmixed= <!doctype html> <html> <head> <title>Hello from Flask</title> </head> <body> <h1>Hello {{ method }}!</h1> <form method="POST"> <label for="d1">d1:</label><input name="d1" id="d1"> <button type="submit">POST Submit</button> </form> <ol> {% for k, v in data.items() %} <li>{{ k }}: {{ v }}</li> {% endfor %} </ol> </body> </html> ``` ---- ### 題外話 Restful API 現在有很多單頁式網站,全部的資料都由 AJAX 去做更新,沒有跳頁轉換的白頁問題,而 AJAX 目前流行的有 Restful API、Graph API 等。 ---- 何謂 Restful API 呢?就是全部的網址都是名詞,而要怎麼分辨目前的增刪修的行為呢?,這時候之前講到的 GET/POST/PATCH/PUT/DELETE 就是重點了 ---- 而且這種方式的回應都大多只需要回應 200 OK, 201 CREATE, 204 NO CONTENT, 404 NOT FOUND, 而不用煩惱轉址問題(前端處理) --- 以上為最基本的 Flask 說明,我們補個資料庫連線後,就開始做一個小網站吧~ 就來個最簡單的縮短網址服務吧 ---- 首先是資料庫連線 用到了套件 flask-SQLAlchemy pymysql ```bash= pip install flask-sqlalchemy pymysql ``` ---- 想一想,縮網址服務需要哪些資料庫欄位 1. 目標網址 (type: Text) 2. 點擊次數 (type: Integer) 3. 建立者 (type: String/User) ---- ```python= from flask import Flask, request, render_template from flask import redirect, url_for from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = \ 'sqlite:///reurl.db' db = SQLAlchemy(app) class Url(db.Model): id = db.Column(db.Integer, primary_key=True) url = db.Column(db.Text, nullable=False) clicks = db.Column(db.Integer, default=0) ``` ---- 我們在建立一個檔案 create_table.py,並執行他 資料表就建起來了 ```python= from main import db db.drop_all() db.create_all() ``` ---- 再來呢,建一個路由來建立短網址吧 ```python= @app.route('/url', methods=['GET', 'POST']) def reUrl(): if request.method == 'POST': url = request.form.get('url') error_message = None short_url = None if url: u = Url(url=url) db.session.add(u) db.session.commit() db.session.refresh(u) # 要 refresh 才能拿到 id 喔 short_url = url_for('sUrl', id=u.id, _external=True) ``` ---- ```python=15 else: error_message = 'Error: 網址為空' return render_template('create_url.html', msg=error_message, short_url=short_url) return render_template('create_url.html') ``` ---- create_url.html ```htmlembedded= {% if short_url %} <span>短網址已建立: <a href='{{ short_url }}'>{{ short_url }}</a> </span> {% endif %} {% if msg %} <span>MSG: {{ msg }}</span> {% endif %} <form method="POST"> <label for="url">URL:</label> <input name="url" id="url"> <button type="submit">Submit</button> </form> ``` ---- 建立完了,總要幫我們轉址,並增加點擊次數 ```python= @app.route('/u/<int:id>', methods=['GET']) def sUrl(id): url = Url.query.get(id) url.clicks += 1 db.session.commit() return redirect(url.url) ``` ---- 來試看看吧 http://127.0.0.1:5000/url ---- 建一個頁面列出現在的縮網址吧 ```python= @app.route('/urls', methods=['GET']) def getUrlList(): urls = Url.query.all() return render_template('list_url.html', urls=urls) ``` ---- list_url.html ```htmlmixed= <table> <thead> <tr> <th>id</th> <th>url</th> <th>origin url</th> <th>clicks</th> </tr> </thead> ``` ---- ```htmlmixed=10 {% for url in urls %} <tr> <td>{{ url.id }}</td> <td> <a href="{{ url_for('sUrl', id=url.id) }}"> {{ url_for('sUrl', id=url.id, _external=True) }} </a> </td> <td>{{ url.url }}</td> <td>{{ url.clicks }}</td> </tr> {% endfor %} </table> ``` ---- http://127.0.0.1:5000/urls ![](https://i.imgur.com/DCL0Bu5.png) --- # Session ---- 我們在前面再加入一個 User 的類別吧 ```python= class User(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(80), nullable=False) username = db.Column(db.String(80), nullable=False) password = db.Column(db.String(80), nullable=False) def __repr__(self): return '<User {}>'.format(self.username) ``` ---- 並修改 Url 類別,加入以下欄位 ```python= creater_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) creater = db.relationship('User', backref=db.backref('urls', lazy=True)) ``` ---- 再來,安全性從小做起,密碼要單向 hash,所以我們裝 `flask-bcrypt` ```bash= pip install flask-bcrypt ``` ---- 並在 `main.py` 最前方內加入 ```python= from flask import session from flask_bcrypt import Bcrypt app = Flask(__name__) app.secret_key = 'eU\x88\x0f=\xa7\xf8\x8aqF\xfb\xb5E-\\\xf2' bcrypt = Bcrypt(app) ``` ---- 並加入註冊頁面 ```python= @app.route('/register', methods=['GET', 'POST']) def register(): msg = '' if request.method == 'POST': f_username = request.form.get('username') f_password = request.form.get('password') f_name = request.form.get('name') if f_username and f_password and f_name: b_password = \ bcrypt.generate_password_hash(f_password)\ .decode('utf-8') ``` ---- ```python=14 user = User(username=f_username, password=b_password, name=f_name) db.session.add(user) db.session.commit() msg = 'Success: 帳號建立成功' else: msg = 'Error: 表單不能為空' return render_template('register.html', msg=msg) ``` ---- register.html ```htmlmixed= {% if msg %} <span>MSG: {{ msg }}</span> {% endif %} <form method="post"> <p><label>Name:</label> <input type="text" name="name"></p> <p><label>Userame:</label> <input type="text" name="username"></p> <p><label>Password:</label> <input type="password" name="password"></p> <p><input type="submit" value="Register"></p> </form> ``` ---- 也要登入了 ```python= @app.route('/login', methods=['GET', 'POST']) def login(): error_message = '' if request.method == 'POST': f_username = request.form.get('username') f_password = request.form.get('password') user = User.query.filter_by(username=f_username)\ .first() if bcrypt.\ check_password_hash(user.password, f_password): session['username'] = request.form['username'] return redirect(url_for('index')) error_message = 'Error: 密碼錯誤' return render_template('login.html', msg=error_message) ``` ---- login.html ```htmlmixed= {% if msg %} <span>MSG: {{ msg }}</span> {% endif %} <form method="post"> <p><label>Userame:</label> <input type="text" name="username"></p> <p><label>Password:</label> <input type="password" name="password"></p> <p><input type="submit" value="Login"></p> </form> ``` ---- 登出 ```python= @app.route('/logout') def logout(): session.pop('username', None) return redirect(url_for('index')) ``` ---- 修改一下首頁 ```htmlmixed= <h1>Hello Flask</h1> <p> {% if session.get('username') %} <h2>Hello User: {{ session['username'] }}</h2> <span><a href="{{ url_for('logout') }}">logout?</a></span> {% else %} <span><a href="{{ url_for('login') }}">Login</a></span> <span><a href="{{ url_for('register') }}">Register</a></span> {% endif %} </p> <ul> <li><a href="{{ url_for('reUrl') }}">縮網址</a></li> <li><a href="{{ url_for('getUrlList') }}">縮列表</a></li> </ul> ``` ---- 再修改一下建立短網址的程式,把建立的人寫入進去 ```python=8 user = None if session.get('username'): user = User\ .query.filter_by( username=session.get('username') ) \ .first() if url: u = Url(url=url, creater=user) ``` ---- 接下來我們在短網址內加入 ```htmlmixed= <td>{{ url.creater.username }}</td> ``` --- # Next? ---- 美化你的專案,學會 HTML5 + CSS3 ---- 佈署你的專案,可以使用 heroku https://devcenter.heroku.com/articles/getting-started-with-python --- # 結論 要學會一個東西,你要先有目標... 然後瘋狂踩雷 ---- ## 沒有動力怎麼辦? VPS 先刷下去,為了不浪費錢 你就會很努力的天天做你的專案
{"metaMigratedAt":"2023-06-15T08:53:36.662Z","metaMigratedFrom":"YAML","title":"Flask 教學","breaks":true,"slideOptions":"{\"theme\":\"solarized\",\"transition\":\"fade\"}","contributors":"[{\"id\":\"b78ee76c-5326-492e-80d9-cd55307898fc\",\"add\":11874,\"del\":1726}]"}
    507 views