Flask基础教学(二)

Flask基础教学(二)

1. 使用数据库

1.1 安装 Flask-SQLAlchemy

首先,使用 pip 安装 Flask-SQLAlchemy 扩展:

pip install Flask-SQLAlchemy

1.2 配置数据库

在 Flask 应用中配置数据库,例如我们将使用 SQLite 数据库:

from flask import Flask  # 导入 Flask 类,用于创建 Flask 应用实例
from flask_sqlalchemy import SQLAlchemy  # 导入 SQLAlchemy 类,用于管理数据库操作

app = Flask(__name__)  # 创建一个 Flask 应用实例
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'  # 配置数据库 URI,使用 SQLite 数据库并命名为 example.db
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  # 禁用 SQLAlchemy 的事件系统,以减少内存开销
db = SQLAlchemy(app)  # 创建一个 SQLAlchemy 实例,将当前 Flask 应用实例与数据库关联起来

1.3 定义数据模型

定义一个简单的用户模型:

# 定义 User 类,它继承自 db.Model
class User(db.Model):
    # 设置 id 为整型,作为主键
    id = db.Column(db.Integer, primary_key=True)
    # 设置 username 为字符串类型,要求唯一,且不能为空
    username = db.Column(db.String(80), unique=True, nullable=False)
    # 设置 email 为字符串类型,要求唯一,且不能为空
    email = db.Column(db.String(120), unique=True, nullable=False)

    # 定义 __repr__ 方法,返回表示该对象的字符串形式
    def __repr__(self):
        return f'<User {self.username}>'

这段代码定义了一个名为 User 的类,它继承自 db.Model。这个类用于表示用户数据,并包含 idusernameemail 三个属性。__repr__ 方法用于定义对象的字符串表示形式。

创建数据库表:

db.create_all()

1.4 增删改查

插入一条新记录:

# 创建一个新的 User 对象,设置用户名为 'John',电子邮件为 'john@example.com'
new_user = User(username='John', email='john@example.com')

# 将新创建的 User 对象添加到数据库会话中,以便将其保存到数据库中
db.session.add(new_user)

# 提交数据库会话中的更改,将新创建的 User 对象保存到数据库中
db.session.commit()

查询所有用户:

users = User.query.all()  # 查询数据库中的所有用户,并将结果赋值给变量 "users"
print(users)              # 打印 "users" 变量的内容,即所有用户的信息

查询单个用户:

# 查询数据库中用户名为 'John' 的用户
user = User.query.filter_by(username='John').first()

# 打印查询结果(如果找到用户,将显示用户信息;如果没有找到,将显示 None)
print(user)

这段代码首先使用 User.query.filter_by(username='John') 查询数据库中用户名为 ‘John’ 的用户。然后,使用 first() 方法获取查询结果中的第一个用户。如果没有找到匹配的用户,first() 将返回 None。最后,我们打印查询结果。如果找到用户,将显示用户信息;如果没有找到,将显示 None

更新用户:

user.username = 'Jane'  # 修改 user 对象的 username 属性值为 'Jane'
db.session.commit()     # 提交更改,将更新后的 user 对象保存到数据库

删除用户:

db.session.delete(user)  # 删除 User 对象实例,表示从数据库中删除这个用户
db.session.commit()       # 提交数据库会话的更改,将删除操作保存到数据库中

1.5 完整示例

# 导入所需模块
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy

# 创建 Flask 应用实例
app = Flask(__name__)

# 配置数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# 初始化 SQLAlchemy 对象
db = SQLAlchemy(app)

# 创建 User 模型
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}>'

# 创建数据库表
db.create_all()

# 定义添加用户的路由
@app.route('/add_user', methods=['POST'])
def add_user():
    # 从表单数据中获取用户名和电子邮件
    username = request.form['username']
    email = request.form['email']

    # 创建新用户对象
    new_user = User(username=username, email=email)

    # 将新用户添加到数据库会话并提交
    db.session.add(new_user)
    db.session.commit()

    # 重定向回首页
    return redirect(url_for('index'))

# 定义显示所有用户的路由
@app.route('/users')
def users():
    # 查询所有用户
    users = User.query.all()

    # 渲染用户列表模板
    return render_template('users.html', users=users)

# 定义首页路由
@app.route('/')
def index():
    # 渲染首页模板
    return render_template('index.html')

# 运行 Flask 应用
if __name__ == '__main__':
    app.run()

在这个示例中,我们创建了一个 User 模型来表示用户数据。我们使用 db.create_all() 创建数据库表。然后,我们定义了两个路由,/add_user 用于添加新用户,/users 用于显示所有用户。

以下是一个简单的 users.html 模板文件,用于显示用户列表:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Users List</title>
  </head>
  <body>
    <h1>Users List</h1>
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Username</th>
          <th>Email</th>
        </tr>
      </thead>
      <tbody>
        {% for user in users %}
        <tr>
          <td>{{ user.id }}</td>
          <td>{{ user.username }}</td>
          <td>{{ user.email }}</td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
    <a href="{{ url_for('index') }}">Back to Home</a>
  </body>
</html>

这个模板文件包含一个表格,用于显示用户的 ID、用户名和电子邮件。{% for user in users %}{% endfor %} 之间的代码会为 users 列表中的每个用户生成一个表格行。{{ user.id }}{{ user.username }}{{ user.email }} 分别用于显示用户的 ID、用户名和电子邮件。在页面底部,还有一个链接可以返回到主页。

以下是一个简单的 index.html 文件内容。该文件包含一个表单,用于输入用户名和电子邮件,以及一个链接,用于浏览所有用户:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask App</title>
</head>
<body>
    <h1>Welcome to the Flask App</h1>
    <form method="POST" action="{{ url_for('add_user') }}">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" required>
        <br>
        <label for="email">Email:</label>
        <input type="email" id="email" name="email" required>
        <br>
        <input type="submit" value="Add User">
    </form>
    <br>
    <a href="{{ url_for('users') }}">View All Users</a>
</body>
</html>

这个 index.html 模板包含了一个表单,用于提交用户名和电子邮件到 /add_user 路由。表单的 action 属性设置为 {{ url_for('add_user') }},这样 Flask 就知道将表单数据提交到哪个路由。页面底部的链接指向用户列表页面,通过 {{ url_for('users') }} 指定。

2. 用户认证

2.1 安装 Flask-Login

使用 pip 安装 Flask-Login 扩展:

pip install Flask-Login

2.2 配置用户认证

在 Flask 应用中配置 Flask-Login:

from flask_login import LoginManager  # 导入 Flask-Login 的 LoginManager 类

login_manager = LoginManager()  # 创建一个 LoginManager 对象
login_manager.init_app(app)     # 将 Flask 应用初始化到 LoginManager 对象中
  1. from flask_login import LoginManager:这行代码从 flask_login 模块中导入 LoginManager 类。LoginManager 类用于处理用户登录、登出和会话管理。
  2. login_manager = LoginManager():这行代码创建了一个 LoginManager 类的实例,用于处理用户认证相关的操作。
  3. login_manager.init_app(app):这行代码将 Flask 应用 app 初始化到 login_manager 实例中。这使得 login_manager 可以与 Flask 应用一起工作,处理用户认证相关的功能。

2.3 创建用户模型

更新用户模型以支持 Flask-Login:

from flask_login import UserMixin

# 定义 User 类,继承自 UserMixin 和 db.Model
class User(UserMixin, db.Model):
    # ...

为 Flask-Login 定义一个加载用户的函数:

# 注册 Flask-Login 的用户加载回调函数
@login_manager.user_loader
def load_user(user_id):
    # 将 user_id 转换为整数,因为从会话中获取的 user_id 是字符串类型
    user_id = int(user_id)
    # 使用 user_id 从数据库中查询用户,并返回该用户对象
    return User.query.get(user_id)

在这段代码中,我们为 Flask-Login 定义了一个用户加载回调函数。这个函数接受一个参数 user_id,表示要加载的用户的唯一标识。我们需要将这个标识转换为整数(因为从会话中获取的 user_id 是字符串类型),然后使用 User.query.get(user_id) 从数据库中查询该用户。最后,我们返回查询到的用户对象。Flask-Login 会使用这个函数在需要时自动加载用户。

2.4 用户注册与登录

创建注册和登录路由:

from flask import render_template, request, redirect, url_for  # 导入所需的库
from flask_login import login_user, logout_user  # 导入登录、登出相关函数

# 定义注册路由
@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':  # 当提交注册表单时
        username = request.form['username']  # 获取表单中的用户名
        email = request.form['email']  # 获取表单中的电子邮件
        new_user = User(username=username, email=email)  # 创建新用户对象
        db.session.add(new_user)  # 添加新用户对象到数据库会话
        db.session.commit()  # 提交数据库会话以保存更改
        return redirect(url_for('login'))  # 重定向到登录页面
    return render_template('register.html')  # 渲染注册页面模板

# 定义登录路由
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':  # 当提交登录表单时
        username = request.form['username']  # 获取表单中的用户名
        user = User.query.filter_by(username=username).first()  # 查询与用户名匹配的用户
        if user:  # 如果找到用户
            login_user(user)  # 使用 Flask-Login 进行登录操作
            return redirect(url_for('index'))  # 重定向到主页
    return render_template('login.html')  # 渲染登录页面模板

创建登出路由:

from flask_login import login_required  # 导入 login_required 装饰器,用于保护需要登录才能访问的视图函数

@app.route('/logout')  # 为登出功能定义路由
@login_required  # 使用 login_required 装饰器,确保只有已登录用户才能访问此视图函数
def logout():  # 定义登出视图函数
    logout_user()  # 使用 Flask-Login 的 logout_user 函数,登出当前用户
    return redirect(url_for('index'))  # 登出成功后,重定向到主页

这段代码主要是实现了用户登出功能。通过使用 Flask-Login 的 login_required 装饰器,我们确保了只有已登录的用户才能访问此视图函数。在视图函数内部,我们调用了 logout_user() 函数来登出当前用户,然后将用户重定向到主页。

2.5 保护路由

使用 login_required 装饰器保护需要用户登录的路由:

# 使用 Flask 的路由装饰器定义一个名为 dashboard 的路由,响应 '/dashboard' URL
@app.route('/dashboard')
# 使用 Flask-Login 的 login_required 装饰器,确保只有已登录用户才能访问此路由
@login_required
# 定义名为 dashboard 的视图函数
def dashboard():
    # 使用 Flask 的 render_template 函数渲染名为 'dashboard.html' 的模板文件,并返回结果
    return render_template('dashboard.html')

此代码定义了一个名为 dashboard 的路由,它响应 /dashboard URL。使用 Flask-Login 的 login_required 装饰器确保只有已登录的用户才能访问此路由。当用户访问此路由时,视图函数 dashboard 会渲染名为 dashboard.html 的模板文件并返回结果。

2.6 完整示例

from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user

app = Flask(__name__)    # 创建 Flask 应用实例
app.config['SECRET_KEY'] = 'mysecretkey'   # 设置应用的密钥
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///auth_example.db'   # 设置数据库的 URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False   # 关闭 SQLAlchemy 的修改跟踪功能
db = SQLAlchemy(app)    # 创建 SQLAlchemy 实例

login_manager = LoginManager()    # 创建 LoginManager 实例
login_manager.init_app(app)    # 初始化 LoginManager 实例
login_manager.login_view = 'login'    # 设置未登录用户的跳转地址

class User(UserMixin, db.Model):   # 创建 User 模型
    id = db.Column(db.Integer, primary_key=True)   # id 主键
    username = db.Column(db.String(80), unique=True, nullable=False)   # 用户名,必须唯一且不能为空
    email = db.Column(db.String(120), unique=True, nullable=False)   # 邮箱,必须唯一且不能为空
    password = db.Column(db.String(255), nullable=False)   # 密码,不能为空

    def __repr__(self):
        return f'<User {self.username}>'   # 返回用户的用户名

db.create_all()    # 创建数据库表

@login_manager.user_loader
def load_user(user_id):   # 定义用户加载函数
    return User.query.get(int(user_id))   # 通过 id 获取用户对象

@app.route('/register', methods=['GET', 'POST'])   # 定义注册路由
def register():
    if current_user.is_authenticated:   # 如果已登录,则直接跳转到主页
        return redirect(url_for('index'))

    if request.method == 'POST':   # 如果是 POST 请求
        username = request.form['username']
        email = request.form['email']
        password = generate_password_hash(request.form['password'], method='sha256')   # 对密码进行哈希加密

        new_user = User(username=username, email=email, password=password)   # 创建新用户
        db.session.add(new_user)   # 添加新用户到数据库
        db.session.commit()   # 提交更改

        flash('Registration successful. You can now log in.', 'success')   # 提示用户注册成功,可以登录
        return redirect(url_for('login'))

    return render_template('register.html')   # 返回注册页面

@app.route('/login', methods=['GET', 'POST'])   # 定义登录路由
def login():
    if current_user.is_authenticated:   # 如果已登录,则直接跳转到主页
        return redirect(url_for('index'))

    if request.method == 'POST':   # 如果是 POST 请求
        username = request.form['username']
        password = request.form['password']
        remember_me = 'remember_me' in request.form

        user = User.query.filter_by(username=username).first()   # 查询用户
        if user and check_password_hash(user.password, password):   # 如果用户存在且密码正确
            login_user(user, remember=remember_me)   # 登录用户
            flash('Logged in successfully.', 'success')
            return redirect(url_for('index'))   # 跳转到主页
        else:
            flash('Invalid username or password.', 'danger')   # 提示用户名或密码错误
    return render_template('login.html')   # 返回登录页面

@app.route('/logout')   # 定义登出路由
@login_required   # 设置路由需要登录才能访问
def logout():
    logout_user()   # 登出用户
    flash('Logged out successfully.', 'success')   # 提示用户登出成功
    return redirect(url_for('login'))   # 跳转到登录页面

@app.route('/')   # 定义主页路由
@login_required   # 设置路由需要登录才能访问
def index():
    return render_template('index.html')   # 返回主页模板

if __name__ == '__main__':
    app.run()   # 运行 Flask 应用

在这个示例中,我们创建了一个 User 模型来表示用户数据。我们使用 db.create_all() 创建数据库表。我们还配置了 Flask-Login 来处理用户认证。我们定义了四个路由:/register 用于用户注册,/login 用于用户登录,/logout 用于用户登出,以及 / 作为主页,需要用户登录才能访问。

以下是一个简单的 login.html 文件内容示例,用于展示登录表单和错误提示信息:

{% extends 'base.html' %}

{% block content %}
  <h1>Login</h1>
  {% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
      {% for category, message in messages %}
        <div class="alert alert-{{ category }}" role="alert">
          {{ message }}
        </div>
      {% endfor %}
    {% endif %}
  {% endwith %}
  <form method="POST" action="{{ url_for('login') }}">
    {{ form.csrf_token }}
    <div class="form-group">
      <label for="username">Username</label>
      {{ form.username(class="form-control", placeholder="Enter username", autofocus=true) }}
    </div>
    <div class="form-group">
      <label for="password">Password</label>
      {{ form.password(class="form-control", placeholder="Enter password") }}
    </div>
    <div class="form-group form-check">
      {{ form.remember_me(class="form-check-input") }}
      <label class="form-check-label" for="remember_me">Remember me</label>
    </div>
    <button type="submit" class="btn btn-primary">Login</button>
  </form>
{% endblock %}

其中,使用了 Flask 提供的模板语言 Jinja2 的语法,用于渲染动态内容。在表单提交时,action 属性会将请求发送到 Flask 应用中的 /login 路由。在表单中,使用了 WTForms 生成的 form.usernameform.passwordform.remember_me 等字段。get_flashed_messages() 函数用于获取 Flask 中的闪现消息,以便在模板中显示成功或失败的提示信息。

以下是一个简单的 register.html 文件的示例,用于展示注册表单和错误提示信息:

{% extends 'base.html' %}

{% block content %}
<div class="row justify-content-md-center mt-5">
  <div class="col-md-6">
    <div class="card">
      <div class="card-body">
        <h3 class="card-title text-center">Create an Account</h3>
        {% with messages = get_flashed_messages() %}
          {% if messages %}
            {% for message in messages %}
              <div class="alert alert-{{ message[1] }}" role="alert">
                {{ message[0] }}
              </div>
            {% endfor %}
          {% endif %}
        {% endwith %}
        <form method="post">
          <div class="form-group">
            <label for="username">Username</label>
            <input type="text" class="form-control" id="username" name="username" placeholder="Enter username" required>
          </div>
          <div class="form-group">
            <label for="email">Email</label>
            <input type="email" class="form-control" id="email" name="email" placeholder="Enter email" required>
          </div>
          <div class="form-group">
            <label for="password">Password</label>
            <input type="password" class="form-control" id="password" name="password" placeholder="Password" required>
          </div>
          <button type="submit" class="btn btn-primary btn-block">Create Account</button>
        </form>
      </div>
    </div>
  </div>
</div>
{% endblock %}

该模板继承了 base.html 模板,包含一个注册表单和用于显示错误消息的逻辑。在提交表单时,将会向 /register 路由发起 POST 请求。

以下是一个简单的 index.html 文件示例,包含欢迎信息和注销按钮:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Welcome</title>
</head>
<body>
    <h1>Welcome, {{ current_user.username }}!</h1>
    <form action="{{ url_for('logout') }}" method="post">
        <input type="submit" value="Logout">
    </form>
</body>
</html>

其中 {{ current_user.username }} 显示当前已登录用户的用户名, url_for('logout') 返回注销路由的 URL,注销按钮通过 POST 方法提交表单,触发注销操作。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Astron-fjh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值