SoFunction
Updated on 2024-11-15

Detailed explanation of the installation and application of the Python Flask framework

1. Installation

1.1 Creating a virtual environment

mkdir myproject
cd myproject
python3 -m venv venv

1.2 Access to the virtual environment

. venv/bin/activate

1.3 Installing flask

pip install Flask

2. Getting Started

2.1 Minimal Demo

Save the following code as

from flask import Flask

app = Flask(__name__)

@("/")
def hello_world():
    return "<p>Hello, World!</p>"

Run the above code:

export FLASK_APP=hello
flask run

Visiting this way: http://127.0.0.1:5000 will see Hello, World!

2.2 Basic knowledge

Here are the basics of flask (a very important foundation that you can read for yourself:link (on a website)

Escaping (utilizing Jinja, cf:link (on a website)

(a few examples below)

@('/')
def index():
    return 'Index Page'

@('/hello')
def hello():
    return 'Hello, World'

@('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return f'User {escape(username)}'

@('/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}'

@('/path/<path:subpath>')
def show_subpath(subpath):
    # show the subpath after /path/
    return f'Subpath {escape(subpath)}'

Methods

@('/login', methods=['GET', 'POST'])
def login():
    if  == 'POST':
    else:

Files (url_for('static', filename=''))

Templates (refer to Jinja for this one)

Uploads, Cookies, Redirects and Errors, About Responses, APIs with JSON, Sessions, Message Flashing, Logging, etc. We'll come back to them when we actually use them.

3. Deconstructing the official website guide Demo

Section 1 shows you how to quickly build a flask environment using the python virtual environment; Section 2 takes you through a brief familiarization with the programming rules (or style) of flask.

When you start this section, make sure you follow the code in section 2 to the official website! Because, instead of building a flask server step-by-step, we're going to analyze this section by taking what we've built and analyzing it in reverse.

3.1 Cloning and Code Architecture Analysis

$ git clone /pallets/flask
$ cd flask
$ cd examples/tutorial

The code directory structure is as follows:

3.2 Entry files

def create_app(test_config=None):
    """Create and configure an instance of the Flask application."""
    # 1-Creating a Flask Instance
    # and set up some parameters that the APP will need
    app = Flask(__name__, instance_relative_config=True)
    .from_mapping(
        # a default secret that should be overridden by instance config
        SECRET_KEY="dev",
        # store the database in the instance folder
        DATABASE=(app.instance_path, ""),
    )

	# 2-Tested
    if test_config is None:
        # load the instance config, if it exists, when not testing
        .from_pyfile("", silent=True)
    else:
        # load the test config if passed in
        (test_config)

	# 3-Create a folder to store files generated by the DB runtime.
    # ensure the instance folder exists
    try:
        (app.instance_path)
    except OSError:
        pass

    @("/hello")
    def hello():
        return "Hello, World!"

    # register the database commands
    # 3.3 Database setup (add a new init_db command for flask so that hitting flask init_db directly will generate the table)
    from flaskr import db

    db.init_app(app)

    # apply the blueprints to the app
    # #### 3.4 Blueprints and views (managing organizational views based on blueprints, views registered to blueprints, blueprints registered to applications)
    from flaskr import auth, blog

    app.register_blueprint()
    app.register_blueprint()

    # make url_for('index') == url_for('')
    # in another app, you might define a separate main index here with
    # , 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 Database setup

The project uses SQLite as the database (Python is built-in, eliminating installation and configuration work).

file

SQLite data is stored in tables, and you need to create a table before adding, deleting, or retrieving data from the table. In this project, we wrote SQL statements to create tables. A user table and a post table are created.

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) Connecting and disconnecting from the database

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:
         = (
            current_app.config["DATABASE"], detect_types=sqlite3.PARSE_DECLTYPES
        )
        .row_factory = 

    return 


def close_db(e=None):
    """If this request connected to the database, close the
    connection.
    """
    db = ("db", None)

    if db is not None:
        ()

g is a special structure that is generated for each request.

3) Database initialization (table generation)

Section 1 is about building tables, so how do you execute the table building commands in that section? This is what init_db does.

def init_db():
    """Clear existing data and create new tables."""
    db = get_db()      # Get the database (create it if it doesn't exist)
    
	# Read the SQL commands in and execute the SQL commands with the
    with current_app.open_resource("") as f:
        (().decode("utf8"))   

4) Register init_db as a flask command

Since the database initialization doesn't need to be run every time the database is started (it's not a function that needs to be executed at runtime), we need to register it as a flask command by simply typingflask init-db It will be possible to implementinit_dbThe method of its realization is as follows:

@("init-db")
@with_appcontext
def init_db_command():
    """Clear existing data and create new tables."""
    init_db()
    ("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) # Call this function when cleaning up after returning a response
    .add_command(init_db_command) # Add a new command that can be called with the flask command

Thus, after execution, the file will appear in the instance folder.

3.4 Blueprints and views

A blueprint is a way to organize a set of related views and other code. Instead of registering views and other code directly with the application, they register with the blueprint. The blueprint is then registered with the application when it becomes available in the factory function.

There are two blueprints in the project: auth and blog.

bp = Blueprint("auth", __name__, url_prefix="/auth")   # in 
bp = Blueprint("blog", __name__) # in 

The parameters are: the name of the blueprint, import_name (usually __name__), and the url prefix.

[1]. Official Demo Github Repository

1) auth view

There are three main routes here:

@("/register", methods=("GET", "POST"))
def register():
...

@("/login", methods=("GET", "POST"))
def login():
...

@("/logout")
def logout():

2) Blog View

There are four main routes here:

@("/")
def index():
...

@("/create", methods=("GET", "POST"))
@login_required
def create():
...

@("/<int:id>/update", methods=("GET", "POST"))
@login_required
def update(id):
...

@("/<int:id>/delete", methods=("POST",))
@login_required
def delete(id):
...

3) Introduction to the implementation of each function in the registration view

enrollment

The registration logic is: first get username and password from POST, then call the database insert operation:

  • username = ["username"]
  • password = ["password"]
  • ("INSERT INTO user (username, password) VALUES (?, ?)", (username, generate_password_hash(password)),)

log in

The login logic is: first get username and password from POST, then call the database query operation to get the user's password, and then do the password matching:

  • user = ("SELECT * FROM user WHERE username = ?",username,)).fetchone()
  • check_password_hash(user["password"], password)

After the password is matched, a session needs to be created:

if error is None:
    # store the user id in a new session and return to the index
    ()
    session["user_id"] = user["id"]
    return redirect(url_for("index"))

deregister

Logging out requires clearing the session:

()

Session

The session logic is as follows: register a method to execute before any URL request, and do session management in it:

@bp.before_app_request
def load_logged_in_user():
    user_id = ('user_id')

    if user_id is None:
         = None
    else:
         = get_db().execute(
            'SELECT * FROM user WHERE id = ?', (user_id,)
        ).fetchone()

Other View Usage Authentication

What should I do if other Views also want to use authentication? Implement the login_required function in to determine if the user is null, if it is null, then jump to the login page:

def login_required(view):
@(view)
def wrapped_view(**kwargs):
    if  is None:
        return redirect(url_for(''))

    return view(**kwargs)

return wrapped_view

4) Introduction to the implementation of each function in the blog view

Show all blogs

The logic is as follows: perform a database query operation to get all the blogs and then load them:

@("/")
def index():
    """Show all the posts, most recent first."""
    db = get_db()
    posts = (
        "SELECT , title, body, created, author_id, username"
        " FROM post p JOIN user u ON p.author_id = "
        " ORDER BY created DESC"
    ).fetchall()
    return render_template("blog/", posts=posts)

Create a blog

The logic is as follows: the function is preceded by@login_required prefix, so that it can automatically determine whether it has been logged in or not, otherwise jump to the login page; create a blog is to get the title and content, and then call the insert command to insert:

@("/create", methods=("GET", "POST"))
@login_required
def create():
    """Create a new post for the current user."""
    if  == "POST":
        title = ["title"]
        body = ["body"]
        error = None

        if not title:
            error = "Title is required."

        if error is not None:
            flash(error)
        else:
            db = get_db()
            (
                "INSERT INTO post (title, body, author_id) VALUES (?, ?, ?)",
                (title, body, ["id"]),
            )
            ()
            return redirect(url_for(""))

    return render_template("blog/")

Updating and deleting blogs

For updating and deleting blogs, you need to pass in an id, and then there is an internal function to determine if that id exists:

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 , title, body, created, author_id, username"
            " FROM post p JOIN user u ON p.author_id = "
            " WHERE  = ?",
            (id,),
        )
        .fetchone()
    )

    if post is None:
        abort(404, f"Post id {id} doesn't exist.")

    if check_author and post["author_id"] != ["id"]:
        abort(403)

    return post

Therefore, the logic of the update is as follows:

@("/<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  == "POST":
        title = ["title"]
        body = ["body"]
        error = None

        if not title:
            error = "Title is required."

        if error is not None:
            flash(error)
        else:
            db = get_db()
            (
                "UPDATE post SET title = ?, body = ? WHERE id = ?", (title, body, id)
            )
            ()
            return redirect(url_for(""))

    return render_template("blog/", post=post)

The logic for deletion is as follows:

@("/<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()
    ("DELETE FROM post WHERE id = ?", (id,))
    ()
    return redirect(url_for(""))

4. Other

There are others that people need to see after they've played with it:

  • Engineering Deployment Installation
  • Engineering Automation Testing

5. Run up DEMO

Finally, let's run the demo to see how it works:

1) In the tutorial directory, create a virtual environment and install Flask:

python3 -m venv venv
. venv/bin/activate
pip install Flask

2) Run as a developer:

export FLASK_APP=flaskr
export FLASK_ENV=development
flask init-db
flask run

The effect is as follows:

The above is a detailed explanation of the installation and application of Python Flask framework in detail, more information about Python Flask framework please pay attention to my other related articles!