網站首頁 編程語言 正文
1.安裝
1.1 創建虛擬環境
mkdir myproject cd myproject python3 -m venv venv
1.2 進入虛擬環境
. 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>"
運行上述代碼:
export FLASK_APP=hello flask run
這樣訪問:http://127.0.0.1:5000?會看到 Hello, World!
2.2 基本知識
這里有 flask 的基本知識(非常重要的基礎,大家可以自己看:鏈接
1.HTML Escaping (利用 Jinja,參考:鏈接
2.Routing (下面幾個例子)
@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 (這個參考之前的 Jinja)
6.File Uploads、Cookies、Redirects and Errors、About Responses、APIs with JSON、Sessions、Message Flashing、Logging 這些等我們實際用到時再過來看
3.解構官網指導 Demo
第 1 節教大家如何利用 python 虛擬環境,快速構建 flask 環境;第 2 節帶著大家簡單熟悉了 flask 的編程規則(或風格)。
大家在著手本節時,務必將第 2 節中的基礎的代碼跟著官網敲一下!因為,這一節我們不是由簡到難一步步搭建 flask 服務器,而是直接拿搭建好的反過來分析。
3.1 克隆與代碼架構分析
$ git clone https://github.com/pallets/flask $ cd flask $ cd examples/tutorial
代碼目錄結構如下:
3.2 入口文件?init.py
def create_app(test_config=None): """Create and configure an instance of the Flask application.""" # 1-創建一個 Flask 實例 # 并設置一些 APP 需要用到的參數 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-創建一個文件夾,用來存 DB 運行時的產生的文件 # 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 數據庫設置(為 flask 新增一個 init_db 命令,這樣直接敲 flask init_db 就能生成表) from flaskr import db db.init_app(app) # apply the blueprints to the app # #### 3.4 藍圖和視圖(基于藍圖來管理組織視圖,視圖注冊到藍圖,藍圖注冊到應用) 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 數據庫設置
該項目采用了 SQLite 作為數據庫(Python 內置了,免去安裝和配置工作)。
1.SQL 文件 schema.sql
SQLite 的數據存儲在表格中,在向表格增刪改查數據前,需要先建表。該項目中的 schema.sql 編寫了建表的 SQL 語句。分別創建了一個 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)與數據庫建立連接與斷開
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 是一個特殊結構,對于每次請求,會產生一個。
3)數據庫初始化(生成表)
第 1 節的 schema.sql 用于建表,那么如何執行其中的建表命令呢? db.py 中的 init_db 就是干這個事情的。
def init_db(): """Clear existing data and create new tables.""" db = get_db() # 獲取數據庫(如果沒有則創建) # 讀取 schema.sql 中的 SQL 命令,并用 db.executescript 執行 SQL 命令 with current_app.open_resource("schema.sql") as f: db.executescript(f.read().decode("utf8"))
4)將 init_db 注冊為 flask 命令
由于數據庫初始化并不需要每次啟動數據庫時運行(不屬于運行時需要執行的函數),我們需要將注冊成 flask 一個指令,只要在命令行中敲?flask init-db
?就能夠執行?init_db
,其實現方法如下:
@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) # 在返回響應后進行清理時調用該函數 app.cli.add_command(init_db_command) # 添加一個可以用flask命令調用的新命令
這樣,執行完之后,flask.sqlite 文件將會出現在 instance 文件夾。
3.4 藍圖和視圖
藍圖是一種組織一組相關視圖和其他代碼的方法。它們不是直接向應用程序注冊視圖和其他代碼,而是向藍圖注冊。然后,當藍圖在factory函數中可用時,它將在應用程序中注冊。
該項目中有兩個藍圖:auth 和 blog
bp = Blueprint("auth", __name__, url_prefix="/auth") # in auth.py bp = Blueprint("blog", __name__) # in blog.py
參數分別是:藍圖的名字,import_name(一般為 __name__),url 前綴
[1].官方 Demo Github 倉庫
1)auth 視圖
這里主要有三個路由:
@bp.route("/register", methods=("GET", "POST")) def register(): ... @bp.route("/login", methods=("GET", "POST")) def login(): ... @bp.route("/logout") def logout():
2)blog 視圖
這里主要有四個路由:
@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)注冊視圖中各個功能實現介紹
注冊
注冊邏輯為:首先從 POST 中獲取 username 和 password,然后調用數據庫插入操作:
username = request.form["username"]
password = request.form["password"]
db.execute("INSERT INTO user (username, password) VALUES (?, ?)", (username, generate_password_hash(password)),)
登錄
登錄邏輯為:首先從 POST 中獲取 username 和 password,然后調用數據庫查詢操作,獲取該用戶的密碼,然后進行密碼匹配:
user = db.execute("SELECT * FROM user WHERE username = ?",username,)).fetchone()
check_password_hash(user["password"], password)
密碼匹配后,需要創建 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 邏輯如下:注冊一個方法,讓其在任何 URL 請求之前執行,在其中做 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 使用認證
其他 View 也想使用認證該如何做?在 auth.py 中實現 login_required 函數,判斷 user 是否為空,如果為空,則跳轉到登錄頁面:
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)博客視圖中各個功能實現介紹
展示所有博客
邏輯如下:執行數據庫查詢操作,獲取所有博客,然后加載:
@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)
創建博客
邏輯如下:函數前加上?@login_required
?前綴,這樣就能自動判斷是否已經登錄,否則跳到登錄頁面;創建博客就是獲取標題和內容,然后調用插入命令,進行插入:
@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")
更新和刪除博客
更新和刪除博客,需要傳入一個 id,然后有一個內部函數用于判斷該 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 目錄下,創建虛擬環境,并安裝 Flask:
python3 -m venv venv . venv/bin/activate pip install Flask
2)以開發者方式運行:
export FLASK_APP=flaskr export FLASK_ENV=development flask init-db flask run
效果如下:
原文鏈接:https://www.cnblogs.com/zjutlitao/p/16218348.html
相關推薦
- 2022-06-30 利用Python刪除電腦中重復文件的方法_python
- 2022-09-07 Redis?sentinel哨兵集群的實現步驟_Redis
- 2022-04-30 Python中類變量和實例變量的區別_python
- 2022-08-07 pandas時間序列之pd.to_datetime()的實現_python
- 2022-07-22 Mybatis為實體類自定義別名的兩種方式
- 2022-11-10 利用C++實現獲取文件夾下所有文件名_C 語言
- 2022-03-24 C++?Primer的變量和基本類型詳解_C 語言
- 2022-02-24 將antd中的Tree組件放在Form表單里面
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支