詳解Python Flask框架的安裝及應(yīng)用
1.安裝
1.1 創(chuàng)建虛擬環(huán)境
mkdir myproject cd myproject python3 -m venv venv
1.2 進(jìn)入虛擬環(huán)境
. venv/bin/activate
1.3 安裝 flask
pip install Flask
2.上手
2.1 最小 Demo
將下列代碼保存為 hello.py:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
運(yùn)行上述代碼:
export FLASK_APP=hello flask run
這樣訪問:http://127.0.0.1:5000 會(huì)看到 Hello, World!
2.2 基本知識(shí)
這里有 flask 的基本知識(shí)(非常重要的基礎(chǔ),大家可以自己看:鏈接
1.HTML Escaping (利用 Jinja,參考:鏈接
2.Routing (下面幾個(gè)例子)
@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 f'User {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 f'Post {post_id}'
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# show the subpath after /path/
return f'Subpath {escape(subpath)}'
3.HTTP Methods
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
else:
4.Static Files (url_for('static', filename='style.css'))
5.Rendering Templates (這個(gè)參考之前的 Jinja)
6.File Uploads、Cookies、Redirects and Errors、About Responses、APIs with JSON、Sessions、Message Flashing、Logging 這些等我們實(shí)際用到時(shí)再過來看
3.解構(gòu)官網(wǎng)指導(dǎo) Demo
第 1 節(jié)教大家如何利用 python 虛擬環(huán)境,快速構(gòu)建 flask 環(huán)境;第 2 節(jié)帶著大家簡單熟悉了 flask 的編程規(guī)則(或風(fēng)格)。
大家在著手本節(jié)時(shí),務(wù)必將第 2 節(jié)中的基礎(chǔ)的代碼跟著官網(wǎng)敲一下!因?yàn)?,這一節(jié)我們不是由簡到難一步步搭建 flask 服務(wù)器,而是直接拿搭建好的反過來分析。
3.1 克隆與代碼架構(gòu)分析
$ git clone https://github.com/pallets/flask $ cd flask $ cd examples/tutorial
代碼目錄結(jié)構(gòu)如下:

3.2 入口文件 init.py
def create_app(test_config=None):
"""Create and configure an instance of the Flask application."""
# 1-創(chuàng)建一個(gè) Flask 實(shí)例
# 并設(shè)置一些 APP 需要用到的參數(shù)
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
# a default secret that should be overridden by instance config
SECRET_KEY="dev",
# store the database in the instance folder
DATABASE=os.path.join(app.instance_path, "flaskr.sqlite"),
)
# 2-測試用的
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile("config.py", silent=True)
else:
# load the test config if passed in
app.config.update(test_config)
# 3-創(chuàng)建一個(gè)文件夾,用來存 DB 運(yùn)行時(shí)的產(chǎn)生的文件
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
@app.route("/hello")
def hello():
return "Hello, World!"
# register the database commands
# 3.3 數(shù)據(jù)庫設(shè)置(為 flask 新增一個(gè) init_db 命令,這樣直接敲 flask init_db 就能生成表)
from flaskr import db
db.init_app(app)
# apply the blueprints to the app
# #### 3.4 藍(lán)圖和視圖(基于藍(lán)圖來管理組織視圖,視圖注冊到藍(lán)圖,藍(lán)圖注冊到應(yīng)用)
from flaskr import auth, blog
app.register_blueprint(auth.bp)
app.register_blueprint(blog.bp)
# make url_for('index') == url_for('blog.index')
# in another app, you might define a separate main index here with
# app.route, while giving the blog blueprint a url_prefix, but for
# the tutorial the blog will be the main index
app.add_url_rule("/", endpoint="index")
return app
3.3 數(shù)據(jù)庫設(shè)置
該項(xiàng)目采用了 SQLite 作為數(shù)據(jù)庫(Python 內(nèi)置了,免去安裝和配置工作)。
1.SQL 文件 schema.sql
SQLite 的數(shù)據(jù)存儲(chǔ)在表格中,在向表格增刪改查數(shù)據(jù)前,需要先建表。該項(xiàng)目中的 schema.sql 編寫了建表的 SQL 語句。分別創(chuàng)建了一個(gè) user 表和 post 表。
DROP TABLE IF EXISTS user; DROP TABLE IF EXISTS post; CREATE TABLE user ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL ); CREATE TABLE post ( id INTEGER PRIMARY KEY AUTOINCREMENT, author_id INTEGER NOT NULL, created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, title TEXT NOT NULL, body TEXT NOT NULL, FOREIGN KEY (author_id) REFERENCES user (id) );
2)與數(shù)據(jù)庫建立連接與斷開
def get_db():
"""Connect to the application's configured database. The connection
is unique for each request and will be reused if this is called
again.
"""
if "db" not in g:
g.db = sqlite3.connect(
current_app.config["DATABASE"], detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
"""If this request connected to the database, close the
connection.
"""
db = g.pop("db", None)
if db is not None:
db.close()
g 是一個(gè)特殊結(jié)構(gòu),對(duì)于每次請(qǐng)求,會(huì)產(chǎn)生一個(gè)。
3)數(shù)據(jù)庫初始化(生成表)
第 1 節(jié)的 schema.sql 用于建表,那么如何執(zhí)行其中的建表命令呢? db.py 中的 init_db 就是干這個(gè)事情的。
def init_db():
"""Clear existing data and create new tables."""
db = get_db() # 獲取數(shù)據(jù)庫(如果沒有則創(chuàng)建)
# 讀取 schema.sql 中的 SQL 命令,并用 db.executescript 執(zhí)行 SQL 命令
with current_app.open_resource("schema.sql") as f:
db.executescript(f.read().decode("utf8"))
4)將 init_db 注冊為 flask 命令
由于數(shù)據(jù)庫初始化并不需要每次啟動(dòng)數(shù)據(jù)庫時(shí)運(yùn)行(不屬于運(yùn)行時(shí)需要執(zhí)行的函數(shù)),我們需要將注冊成 flask 一個(gè)指令,只要在命令行中敲 flask init-db 就能夠執(zhí)行 init_db,其實(shí)現(xiàn)方法如下:
@click.command("init-db")
@with_appcontext
def init_db_command():
"""Clear existing data and create new tables."""
init_db()
click.echo("Initialized the database.")
def init_app(app):
"""Register database functions with the Flask app. This is called by
the application factory.
"""
app.teardown_appcontext(close_db) # 在返回響應(yīng)后進(jìn)行清理時(shí)調(diào)用該函數(shù)
app.cli.add_command(init_db_command) # 添加一個(gè)可以用flask命令調(diào)用的新命令
這樣,執(zhí)行完之后,flask.sqlite 文件將會(huì)出現(xiàn)在 instance 文件夾。
3.4 藍(lán)圖和視圖
藍(lán)圖是一種組織一組相關(guān)視圖和其他代碼的方法。它們不是直接向應(yīng)用程序注冊視圖和其他代碼,而是向藍(lán)圖注冊。然后,當(dāng)藍(lán)圖在factory函數(shù)中可用時(shí),它將在應(yīng)用程序中注冊。
該項(xiàng)目中有兩個(gè)藍(lán)圖:auth 和 blog
bp = Blueprint("auth", __name__, url_prefix="/auth") # in auth.py
bp = Blueprint("blog", __name__) # in blog.py
參數(shù)分別是:藍(lán)圖的名字,import_name(一般為 __name__),url 前綴
1)auth 視圖
這里主要有三個(gè)路由:
@bp.route("/register", methods=("GET", "POST"))
def register():
...
@bp.route("/login", methods=("GET", "POST"))
def login():
...
@bp.route("/logout")
def logout():
2)blog 視圖
這里主要有四個(gè)路由:
@bp.route("/")
def index():
...
@bp.route("/create", methods=("GET", "POST"))
@login_required
def create():
...
@bp.route("/<int:id>/update", methods=("GET", "POST"))
@login_required
def update(id):
...
@bp.route("/<int:id>/delete", methods=("POST",))
@login_required
def delete(id):
...
3)注冊視圖中各個(gè)功能實(shí)現(xiàn)介紹
注冊
注冊邏輯為:首先從 POST 中獲取 username 和 password,然后調(diào)用數(shù)據(jù)庫插入操作:
username = request.form["username"]password = request.form["password"]db.execute("INSERT INTO user (username, password) VALUES (?, ?)", (username, generate_password_hash(password)),)
登錄
登錄邏輯為:首先從 POST 中獲取 username 和 password,然后調(diào)用數(shù)據(jù)庫查詢操作,獲取該用戶的密碼,然后進(jìn)行密碼匹配:
user = db.execute("SELECT * FROM user WHERE username = ?",username,)).fetchone()check_password_hash(user["password"], password)
密碼匹配后,需要?jiǎng)?chuàng)建 session:
if error is None:
# store the user id in a new session and return to the index
session.clear()
session["user_id"] = user["id"]
return redirect(url_for("index"))
注銷
注銷需要清空 session:
session.clear()
Session
Session 邏輯如下:注冊一個(gè)方法,讓其在任何 URL 請(qǐng)求之前執(zhí)行,在其中做 Session 管理:
@bp.before_app_request
def load_logged_in_user():
user_id = session.get('user_id')
if user_id is None:
g.user = None
else:
g.user = get_db().execute(
'SELECT * FROM user WHERE id = ?', (user_id,)
).fetchone()
其他 View 使用認(rèn)證
其他 View 也想使用認(rèn)證該如何做?在 auth.py 中實(shí)現(xiàn) login_required 函數(shù),判斷 user 是否為空,如果為空,則跳轉(zhuǎn)到登錄頁面:
def login_required(view):
@functools.wraps(view)
def wrapped_view(**kwargs):
if g.user is None:
return redirect(url_for('auth.login'))
return view(**kwargs)
return wrapped_view
4)博客視圖中各個(gè)功能實(shí)現(xiàn)介紹
展示所有博客
邏輯如下:執(zhí)行數(shù)據(jù)庫查詢操作,獲取所有博客,然后加載:
@bp.route("/")
def index():
"""Show all the posts, most recent first."""
db = get_db()
posts = db.execute(
"SELECT p.id, title, body, created, author_id, username"
" FROM post p JOIN user u ON p.author_id = u.id"
" ORDER BY created DESC"
).fetchall()
return render_template("blog/index.html", posts=posts)
創(chuàng)建博客
邏輯如下:函數(shù)前加上 @login_required 前綴,這樣就能自動(dòng)判斷是否已經(jīng)登錄,否則跳到登錄頁面;創(chuàng)建博客就是獲取標(biāo)題和內(nèi)容,然后調(diào)用插入命令,進(jìn)行插入:
@bp.route("/create", methods=("GET", "POST"))
@login_required
def create():
"""Create a new post for the current user."""
if request.method == "POST":
title = request.form["title"]
body = request.form["body"]
error = None
if not title:
error = "Title is required."
if error is not None:
flash(error)
else:
db = get_db()
db.execute(
"INSERT INTO post (title, body, author_id) VALUES (?, ?, ?)",
(title, body, g.user["id"]),
)
db.commit()
return redirect(url_for("blog.index"))
return render_template("blog/create.html")
更新和刪除博客
更新和刪除博客,需要傳入一個(gè) id,然后有一個(gè)內(nèi)部函數(shù)用于判斷該 id 是否存在:
def get_post(id, check_author=True):
"""Get a post and its author by id.
Checks that the id exists and optionally that the current user is
the author.
:param id: id of post to get
:param check_author: require the current user to be the author
:return: the post with author information
:raise 404: if a post with the given id doesn't exist
:raise 403: if the current user isn't the author
"""
post = (
get_db()
.execute(
"SELECT p.id, title, body, created, author_id, username"
" FROM post p JOIN user u ON p.author_id = u.id"
" WHERE p.id = ?",
(id,),
)
.fetchone()
)
if post is None:
abort(404, f"Post id {id} doesn't exist.")
if check_author and post["author_id"] != g.user["id"]:
abort(403)
return post
因此,更新的邏輯如下:
@bp.route("/<int:id>/update", methods=("GET", "POST"))
@login_required
def update(id):
"""Update a post if the current user is the author."""
post = get_post(id)
if request.method == "POST":
title = request.form["title"]
body = request.form["body"]
error = None
if not title:
error = "Title is required."
if error is not None:
flash(error)
else:
db = get_db()
db.execute(
"UPDATE post SET title = ?, body = ? WHERE id = ?", (title, body, id)
)
db.commit()
return redirect(url_for("blog.index"))
return render_template("blog/update.html", post=post)
刪除的邏輯如下:
@bp.route("/<int:id>/delete", methods=("POST",))
@login_required
def delete(id):
"""Delete a post.
Ensures that the post exists and that the logged in user is the
author of the post.
"""
get_post(id)
db = get_db()
db.execute("DELETE FROM post WHERE id = ?", (id,))
db.commit()
return redirect(url_for("blog.index"))
4.其他
其他還有一些,是大家玩熟了之后才需要看的:
5.跑起 DEMO
最后,我們跑起 Demo 看看效果:
1)在 tutorial 目錄下,創(chuàng)建虛擬環(huán)境,并安裝 Flask:
python3 -m venv venv . venv/bin/activate pip install Flask
2)以開發(fā)者方式運(yùn)行:
export FLASK_APP=flaskr export FLASK_ENV=development flask init-db flask run
效果如下:

以上就是詳解Python Flask框架的安裝及應(yīng)用的詳細(xì)內(nèi)容,更多關(guān)于Python Flask框架的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PyTorch如何使用embedding對(duì)特征向量進(jìn)行嵌入
這篇文章主要介紹了PyTorch如何使用embedding對(duì)特征向量進(jìn)行嵌入問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
Python實(shí)現(xiàn)批量檢測HTTP服務(wù)的狀態(tài)
本文給大家分享的是一個(gè)使用python實(shí)現(xiàn)的批量檢測web服務(wù)可用性的腳本代碼,主要功能有測試一組url的可用性(可以包括HTTP狀態(tài)、響應(yīng)時(shí)間等)并統(tǒng)計(jì)出現(xiàn)不可用情況的次數(shù)和頻率等。2016-10-10
Python實(shí)現(xiàn)名片管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)名片管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
使用Python編寫一個(gè)簡單的tic-tac-toe游戲的教程
這篇文章主要介紹了使用Python編寫一個(gè)簡單的tic-tac-toe游戲的教程,有利于Python初學(xué)者進(jìn)行上手實(shí)踐,需要的朋友可以參考下2015-04-04
Python?實(shí)操顯示數(shù)據(jù)圖表并固定時(shí)間長度
這篇文章主要介紹了Python?實(shí)操顯示數(shù)據(jù)圖表并固定時(shí)間長度,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08

