溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python?Flask框架如何安裝及應(yīng)用

發(fā)布時間:2022-05-31 10:52:32 來源:億速云 閱讀:173 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“Python Flask框架如何安裝及應(yīng)用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“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 會看到 Hello, World!

    2.2 基本知識

    這里有 flask 的基本知識(非常重要的基礎(chǔ),大家可以自己看:鏈接

    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 這些等我們實(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é)時,務(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)如下:

    Python?Flask框架如何安裝及應(yīng)用

    3.2 入口文件 init.py

    def create_app(test_config=None):
        """Create and configure an instance of the Flask application."""
        # 1-創(chuàng)建一個 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)建一個文件夾,用來存 DB 運(yùn)行時的產(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 新增一個 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ù)存儲在表格中,在向表格增刪改查數(shù)據(jù)前,需要先建表。該項(xiàng)目中的 schema.sql 編寫了建表的 SQL 語句。分別創(chuàng)建了一個 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 是一個特殊結(jié)構(gòu),對于每次請求,會產(chǎn)生一個。

    3)數(shù)據(jù)庫初始化(生成表)

    第 1 節(jié)的 schema.sql 用于建表,那么如何執(zhí)行其中的建表命令呢? db.py 中的 init_db 就是干這個事情的。

    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ù)庫初始化并不需要每次啟動數(shù)據(jù)庫時運(yùn)行(不屬于運(yùn)行時需要執(zhí)行的函數(shù)),我們需要將注冊成 flask 一個指令,只要在命令行中敲 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)行清理時調(diào)用該函數(shù)
        app.cli.add_command(init_db_command) # 添加一個可以用flask命令調(diào)用的新命令

    這樣,執(zhí)行完之后,flask.sqlite 文件將會出現(xiàn)在 instance 文件夾。

    3.4 藍(lán)圖和視圖

    藍(lán)圖是一種組織一組相關(guān)視圖和其他代碼的方法。它們不是直接向應(yīng)用程序注冊視圖和其他代碼,而是向藍(lán)圖注冊。然后,當(dāng)藍(lán)圖在factory函數(shù)中可用時,它將在應(yīng)用程序中注冊。

    該項(xiàng)目中有兩個藍(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].官方 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)注冊視圖中各個功能實(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)

    密碼匹配后,需要創(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 邏輯如下:注冊一個方法,讓其在任何 URL 請求之前執(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)博客視圖中各個功能實(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 前綴,這樣就能自動判斷是否已經(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")

    更新和刪除博客

    更新和刪除博客,需要傳入一個 id,然后有一個內(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)用

    到此,相信大家對“Python Flask框架如何安裝及應(yīng)用”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI