MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python使用Flask构建简单Web应用

2024-01-261.5k 阅读

Flask基础概述

Flask是什么

Flask是一个用Python编写的轻量级Web应用框架。它基于Werkzeug WSGI工具包和Jinja2模板引擎。WSGI(Web Server Gateway Interface)是Python中定义Web服务器与Web应用程序之间接口的规范,Werkzeug实现了这个规范,为Flask提供了底层的请求处理等功能。Jinja2则用于动态生成HTML等模板文件,方便将数据与模板结合展示给用户。

Flask之所以轻量级,是因为它核心功能简洁,开发者可以根据项目需求灵活选择和集成各种扩展。例如,如果需要数据库支持,可以添加SQLAlchemy扩展;如果要处理用户认证,Flask - Login是不错的选择。这种灵活性使得Flask既适合快速搭建小型项目,也能在大型复杂应用中发挥重要作用。

安装Flask

在开始使用Flask构建Web应用之前,需要先安装它。假设你已经安装了Python和pip(Python的包管理工具),在命令行中执行以下命令即可安装Flask:

pip install flask

如果你使用的是虚拟环境(强烈推荐,它可以隔离不同项目的Python包环境,避免版本冲突),在创建并激活虚拟环境后执行上述安装命令。例如,使用venv模块创建虚拟环境:

python -m venv myenv
source myenv/bin/activate  # Windows下使用 myenv\Scripts\activate
pip install flask

创建第一个Flask应用

简单的Hello World示例

创建一个新的Python文件,比如app.py,输入以下代码:

from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello, World!'


if __name__ == '__main__':
    app.run()

在这段代码中:

  1. 首先从flask模块导入Flask类。
  2. 创建一个Flask类的实例app__name__是Python的一个内置变量,它表示当前模块的名称。Flask用它来确定应用的根路径等信息。
  3. 使用@app.route装饰器来定义路由。这里@app.route('/')表示当用户访问网站根路径(例如http://127.0.0.1:5000/)时,会执行下面的hello_world函数。
  4. hello_world函数返回字符串Hello, World!,这个字符串会作为HTTP响应的内容返回给客户端。
  5. if __name__ == '__main__':这个条件判断保证了当直接运行这个脚本时,app.run()才会执行。app.run()启动Flask内置的开发服务器,默认监听在127.0.0.1:5000,即本地的5000端口。

在命令行中运行这个脚本:

python app.py

然后在浏览器中访问http://127.0.0.1:5000/,就能看到Hello, World!的页面。

路由与视图函数

  1. 路由定义:路由是Flask应用中URL与处理函数之间的映射关系。通过@app.route装饰器来定义路由。例如,要定义一个处理/about路径的路由:
@app.route('/about')
def about():
    return 'This is an about page'
  1. 动态路由:有时我们需要在URL中传递参数,Flask支持动态路由。例如,要获取用户的ID并展示相关信息,可以这样定义路由:
@app.route('/user/<int:user_id>')
def user_profile(user_id):
    return f'This is the profile of user {user_id}'

在这个例子中,<int:user_id>表示这里接受一个整数类型的参数user_id,并且将其传递给user_profile函数。int是类型转换器,Flask还支持其他类型转换器,如string(默认类型,接受字符串)、floatpath(接受包含斜杠的字符串)等。

  1. HTTP方法:默认情况下,@app.route装饰的视图函数只接受GET请求。如果要处理其他HTTP方法,如POST,可以在@app.route中指定methods参数。例如:
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 处理POST请求的数据,比如获取表单数据
        username = request.form.get('username')
        password = request.form.get('password')
        # 进行登录验证等操作
        return f'Logging in user {username}'
    else:
        # 返回登录表单等内容
        return 'This is the login form'

这里导入了request对象(从flask模块),它包含了客户端发送的请求信息。通过request.method可以判断请求的HTTP方法。

模板引擎Jinja2

Jinja2模板基础

  1. 模板文件创建:在Flask项目中,通常在项目根目录下创建一个templates文件夹来存放模板文件。例如,创建一个index.html模板文件:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>My Flask App</title>
</head>

<body>
    <h1>Welcome to my Flask app</h1>
    <p>{{ message }}</p>
</body>

</html>

在这个模板中,{{ message }}是一个Jinja2变量占位符,它会在渲染模板时被实际的值替换。

  1. 模板渲染:在Flask应用中,使用render_template函数来渲染模板。修改app.py如下:
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def index():
    message = 'This is a sample message'
    return render_template('index.html', message=message)


if __name__ == '__main__':
    app.run()

index函数中,定义了一个message变量,并将其传递给render_template函数。render_template函数第一个参数是模板文件名,后面可以跟着一系列的变量名和对应的值,这些值会在模板中可用。

模板继承与块

  1. 模板继承:模板继承允许我们创建一个基础模板,其他模板可以继承它并根据需要覆盖部分内容。创建一个基础模板base.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>{% block title %}Default Title{% endblock %}</title>
    {% block styles %}
    <style>
        body {
            font-family: Arial, sans - serif;
        }
    </style>
    {% endblock %}
</head>

<body>
    <header>
        <h1>My Flask Site</h1>
    </header>
    {% block content %}
    <p>This is the default content</p>
    {% endblock %}
    <footer>
        <p>&copy; 2023 My Company</p>
    </footer>
    {% block scripts %}
    <script>
        console.log('This is a default script');
    </script>
    {% endblock %}
</body>

</html>

在这个基础模板中,使用{% block %}标签定义了几个块,如titlestylescontentscripts

  1. 子模板继承:创建一个继承自base.html的子模板about.html
{% extends 'base.html' %}

{% block title %}About Us{% endblock %}

{% block content %}
<p>We are a company dedicated to providing great services.</p>
{% endblock %}

about.html中,使用{% extends 'base.html' %}声明继承自base.html,然后通过{% block %}标签覆盖了titlecontent块的内容。在Flask应用中,渲染about.html模板就会按照继承规则展示页面。

@app.route('/about')
def about():
    return render_template('about.html')

模板中的控制结构

  1. 条件判断:在模板中可以使用if - else结构。例如,根据一个变量的值显示不同的内容:
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}</p>
{% else %}
<p>Please log in</p>
{% endif %}
  1. 循环:使用for循环可以遍历列表等可迭代对象。假设在视图函数中有一个用户列表:
@app.route('/users')
def users():
    user_list = [
        {'name': 'Alice', 'age': 25},
        {'name': 'Bob', 'age': 30}
    ]
    return render_template('users.html', user_list=user_list)

users.html模板中:

<ul>
    {% for user in user_list %}
    <li>Name: {{ user.name }}, Age: {{ user.age }}</li>
    {% endfor %}
</ul>

这样就会将用户列表中的每个用户信息展示出来。

处理表单数据

Flask - WTF扩展

  1. 安装:Flask - WTF是一个用于处理表单的Flask扩展,它基于WTForms库。安装命令如下:
pip install flask - wtf
  1. 创建表单类:在项目中创建一个forms.py文件,定义表单类。例如,创建一个简单的登录表单:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired


class LoginForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    submit = SubmitField('Login')

在这个表单类中,StringField用于创建文本输入框,PasswordField用于密码输入框,SubmitField用于提交按钮。validators参数用于添加验证规则,DataRequired表示该字段是必填的。

在视图和模板中使用表单

  1. 视图函数处理:修改app.py来处理登录表单:
from flask import Flask, render_template, request
from forms import LoginForm

app = Flask(__name__)
app.secret_key = 'your_secret_key'


@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        username = form.username.data
        password = form.password.data
        # 进行登录验证逻辑
        return f'Logging in user {username}'
    return render_template('login.html', form=form)


if __name__ == '__main__':
    app.run()

这里创建了LoginForm的实例formform.validate_on_submit()方法会在表单提交时验证数据是否符合验证规则。如果验证通过,获取表单数据进行登录验证等操作。

  1. 模板显示表单:在login.html模板中显示表单:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>

<body>
    <form method="post">
        {{ form.csrf_token }}
        <label for="{{ form.username.id }}">{{ form.username.label }}</label>
        {{ form.username }}
        <br>
        <label for="{{ form.password.id }}">{{ form.password.label }}</label>
        {{ form.password }}
        <br>
        {{ form.submit }}
    </form>
</body>

</html>

{{ form.csrf_token }}用于添加跨站请求伪造(CSRF)保护令牌,这是Flask - WTF自动生成的。其他表单字段通过{{ form.field_name }}的方式显示,标签通过{{ form.field_name.label }}显示。

数据库集成

SQLite与SQLAlchemy

  1. SQLAlchemy介绍:SQLAlchemy是一个强大的数据库抽象层库,Flask - SQLAlchemy是其针对Flask的扩展。它允许我们使用Python代码与各种数据库进行交互,而不需要编写特定数据库的SQL语句。首先安装Flask - SQLAlchemy:
pip install flask - sqlalchemy
  1. 配置数据库:在app.py中配置SQLite数据库:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///myapp.db'
db = SQLAlchemy(app)

这里设置SQLALCHEMY_DATABASE_URI为SQLite数据库文件路径myapp.db,然后创建了SQLAlchemy的实例db

定义数据库模型

  1. 模型类创建:在models.py文件中定义数据库模型类。例如,创建一个用户模型:
from app import db


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return f'<User {self.username}>'

在这个模型类中,id是主键,usernameemail是普通字段,unique=True表示字段值必须唯一,nullable=False表示字段不能为空。__repr__方法用于定义对象的字符串表示形式,方便调试等操作。

数据库操作

  1. 添加数据:在视图函数中添加用户数据:
from models import User


@app.route('/add_user', methods=['POST'])
def add_user():
    username = request.form.get('username')
    email = request.form.get('email')
    new_user = User(username=username, email=email)
    db.session.add(new_user)
    db.session.commit()
    return 'User added successfully'

这里从表单获取用户名和邮箱,创建User对象,使用db.session.add将对象添加到会话中,然后通过db.session.commit提交会话,将数据保存到数据库。

  1. 查询数据:查询所有用户:
@app.route('/users')
def get_all_users():
    users = User.query.all()
    user_list = []
    for user in users:
        user_list.append(f'Username: {user.username}, Email: {user.email}')
    return '<br>'.join(user_list)

User.query.all()查询User表中的所有记录,并将结果展示出来。

  1. 更新数据:更新用户的邮箱:
@app.route('/update_user/<int:user_id>', methods=['POST'])
def update_user(user_id):
    user = User.query.get(user_id)
    if user:
        new_email = request.form.get('email')
        user.email = new_email
        db.session.commit()
        return 'User email updated successfully'
    return 'User not found'

通过User.query.get(user_id)获取指定ID的用户,然后更新其邮箱并提交会话。

  1. 删除数据:删除用户:
@app.route('/delete_user/<int:user_id>', methods=['POST'])
def delete_user(user_id):
    user = User.query.get(user_id)
    if user:
        db.session.delete(user)
        db.session.commit()
        return 'User deleted successfully'
    return 'User not found'

获取用户后使用db.session.delete删除对象并提交会话。

部署Flask应用

生产环境服务器选择

  1. Gunicorn:Gunicorn是一个广泛使用的Python WSGI HTTP服务器。它可以与Flask应用一起部署,提供更好的性能和稳定性。安装命令:
pip install gunicorn
  1. uWSGI:uWSGI也是一个流行的应用服务器,支持多种协议和功能。安装命令:
pip install uwsgi

使用Gunicorn部署

  1. 启动命令:假设你的Flask应用入口文件是app.py,应用实例是app,在项目目录下执行以下命令启动Gunicorn:
gunicorn -w 4 -b 127.0.0.1:8000 app:app

这里-w 4表示使用4个工作进程,-b 127.0.0.1:8000指定绑定的IP地址和端口,app:app表示应用入口文件app.py中的app实例。

  1. 配置文件:可以创建一个配置文件(例如gunicorn.conf.py)来更方便地管理启动参数:
workers = 4
bind = '127.0.0.1:8000'

然后使用以下命令启动:

gunicorn -c gunicorn.conf.py app:app

与Nginx配合部署

  1. Nginx安装与配置:安装Nginx后,在Nginx配置目录(通常是/etc/nginx/sites - available)下创建一个新的配置文件,例如myapp.conf
server {
    listen 80;
    server_name your_domain.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X - Real - IP $remote_addr;
        proxy_set_header X - Forwarded - For $proxy_add_x_forwarded_for;
        proxy_set_header X - Forwarded - Proto $scheme;
    }
}

这里proxy_pass指定将请求转发到Gunicorn运行的地址(127.0.0.1:8000)。然后创建符号链接将配置文件链接到/etc/nginx/sites - enabled目录:

ln -s /etc/nginx/sites - available/myapp.conf /etc/nginx/sites - enabled/

重启Nginx服务使配置生效:

sudo systemctl restart nginx
  1. HTTPS配置:为了安全,可以为网站配置HTTPS。可以使用Let's Encrypt获取免费的SSL证书。安装Certbot:
sudo apt install certbot python3 - certbot - nginx

然后使用Certbot为Nginx配置SSL:

sudo certbot --nginx -d your_domain.com

按照提示操作,Certbot会自动为你的网站配置HTTPS。

通过以上步骤,你可以逐步从创建一个简单的Flask应用,到集成数据库、处理表单,最后部署到生产环境,构建一个完整可用的Web应用。在实际开发中,还需要考虑更多的安全、性能优化等方面的问题,但这些基础知识为进一步深入学习和开发打下了坚实的基础。