Flask 是個輕量級的程式語言,其簡單的程式碼就可以架構出一個簡易的http服務應用。
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!' if __name__ == '__main__': app.debug = True app.run()
一個網站裏面,會有各式各樣的路徑,而這些路徑,在網站裏面稱作路由,會決定哪個網址由哪段程式碼處理
@app.route('/') def index(): return 'Index Page' @app.route('/hello') def hello(): return 'Hello, World'
除了這些靜態路由,當然還有所謂的動態路由
@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 字串 |
Flask 預設使用 JinJa2 模板排版引擎
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
以下是一個簡易模板的內容
<!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 去獲得網址,這點可以讓網址產生是動態的,在網頁裡可以顯示出該段的網址
一般網頁只能使用 Get/Post
Put/Patch/Delete 需要使用 JavaScript 來輔助
@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
<!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>
現在有很多單頁式網站,全部的資料都由 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
pip install flask-sqlalchemy pymysql
想一想,縮網址服務需要哪些資料庫欄位
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,並執行他
資料表就建起來了
from main import db db.drop_all() db.create_all()
再來呢,建一個路由來建立短網址吧
@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)
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
{% 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>
建立完了,總要幫我們轉址,並增加點擊次數
@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)
建一個頁面列出現在的縮網址吧
@app.route('/urls', methods=['GET']) def getUrlList(): urls = Url.query.all() return render_template('list_url.html', urls=urls)
list_url.html
<table> <thead> <tr> <th>id</th> <th>url</th> <th>origin url</th> <th>clicks</th> </tr> </thead>
{% 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>
我們在前面再加入一個 User 的類別吧
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 類別,加入以下欄位
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
pip install flask-bcrypt
並在 main.py
最前方內加入
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)
並加入註冊頁面
@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')
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
{% 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>
也要登入了
@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
{% 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>
登出
@app.route('/logout') def logout(): session.pop('username', None) return redirect(url_for('index'))
修改一下首頁
<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>
再修改一下建立短網址的程式,把建立的人寫入進去
user = None if session.get('username'): user = User\ .query.filter_by( username=session.get('username') ) \ .first() if url: u = Url(url=url, creater=user)
接下來我們在短網址內加入
<td>{{ url.creater.username }}</td>
美化你的專案,學會 HTML5 + CSS3
佈署你的專案,可以使用 heroku
https://devcenter.heroku.com/articles/getting-started-with-python
要學會一個東西,你要先有目標…
然後瘋狂踩雷
VPS 先刷下去,為了不浪費錢
你就會很努力的天天做你的專案