后端_Flask学习笔记

目录

1、安装Flask

2、创建第一个flask

[3、Jinja2 模板](#3、Jinja2 模板)

3.1案例

3.2过滤器

3.3控制结构

[1. 条件表达式(If-Else)](#1. 条件表达式(If-Else))

[2. 循环(For Loop)](#2. 循环(For Loop))

[3. 循环控制(Loop Controls)](#3. 循环控制(Loop Controls))

[4. 继承(Template Inheritance)](#4. 继承(Template Inheritance))

3.4静态文件

3.5URL生成

4、Flask-WTF表单处理

[1. 安装 Flask-WTF](#1. 安装 Flask-WTF)

[2. 创建表单类](#2. 创建表单类)

[3. 在视图函数中处理表单](#3. 在视图函数中处理表单)

[4. 在模板中渲染表单](#4. 在模板中渲染表单)

[5. 表单验证](#5. 表单验证)

[6. 显示闪现消息](#6. 显示闪现消息)

5、文件上传

[创建 Flask 应用实例](#创建 Flask 应用实例)

定义允许的文件类型

创建表单类

定义上传路由

模板渲染

6、数据库集成

安装Flask-SQLAlchemy

定义模型类

初始化数据库

[数据库迁移工具 Flask-Migrate](#数据库迁移工具 Flask-Migrate)

[1. 安装 Flask-Migrate](#1. 安装 Flask-Migrate)

[2. 初始化 Flask-Migrate](#2. 初始化 Flask-Migrate)

[3. 创建迁移文件](#3. 创建迁移文件)

[基本 CRUD 操作](#基本 CRUD 操作)

[1 创建(Create)](#1 创建(Create))

[2 读取(Read)](#2 读取(Read))

[3 更新(Update)](#3 更新(Update))

[4 删除(Delete)](#4 删除(Delete))

7.用户认证与授权

[7.1 Flask-Login扩展](#7.1 Flask-Login扩展)

[1. 安装 Flask-Login](#1. 安装 Flask-Login)

[2.初始化 Flask 应用和扩展(app.py)](#2.初始化 Flask 应用和扩展(app.py))

3.定义用户模型(models.py)

4.定义表单类(forms.py)

5.创建模板文件

templates/login.html

7.2Flask-Bcrypt密码哈希

[1. 安装 & 初始化](#1. 安装 & 初始化)

2.密码哈希

3.应用场景代码

注册

登录

修改密码

[7.3 Flask-Principal 基于角色的访问控制](#7.3 Flask-Principal 基于角色的访问控制)

[1. 安装 & 蓝图结构](#1. 安装 & 蓝图结构)

[2. 初始化](#2. 初始化)

[3. 用户模型(models.py)](#3. 用户模型(models.py))

[4. 登录动作](#4. 登录动作)

[5. 视图层](#5. 视图层)

A) 装饰器 装饰器)

B) 模板内隐藏按钮 模板内隐藏按钮)

7.4Flask-Security

安装

先放着之后在学习

[7.5REST API开发](#7.5REST API开发)


个人学习 学习笔记主要参考 【Python Web】一文搞懂Flask框架:从入门到实战的完整指南-CSDN博客
Flask入门教程(非常详细),从零基础入门到精通,看完这一篇就够了-CSDN博客

1、安装Flask

复制代码
#创建虚拟环境
python -m venv venv

不排除在新建一个python项目时已经有了一个虚拟环境了,就不需要再重复创建,只需要激活就可以了。

复制代码
#激活虚拟环境
venv\Scripts\activate

安装flask

复制代码
 pip install flask -i https://pypi.mirrors.ustc.edu.cn/simple/

验证安装

复制代码
python -c "import flask; print(flask.__version__)"

如果报错要求下载这些依赖项

Flask 的主要依赖项包括:

  • Werkzeug

  • Jinja2

  • MarkupSafe

  • click

  • itsdangerous

那么就再运行下面这行代码

复制代码
pip install --upgrade flask  -i https://pypi.mirrors.ustc.edu.cn/simple/

myproject/

├── app/

│ ├── init.py

│ ├── routes.py

│ ├── templates/

│ │ └── index.html

│ ├── static/

│ │ └── style.css

│ └── models.py

├── venv/

├── config.py

└── run.py

2、创建第一个flask

python 复制代码
from flask import Flask

#创建flask实例
app = Flask(__name__)

#定义路由和视图函数
@app.route('/')
def home():
    return 'hello world'

@app.route('/about')
def about():
    return 'This is the about page'

#启动应用
if __name__ == '__main__':
    app.run(debug=True)

3、Jinja2 模板

3.1案例

index.html 文件中,可以使用 Jinja2 模板语法来动态生成 HTML 内容。示例模板。

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }}</title>
</head>
<body>
    <h1>Welcome, {{ name }}!</h1>
    <h2>Messages</h2>
    <ul>
        {% for message in messages %}
            <li>{{ message }}</li>
        {% endfor %}
    </ul>
</body>
</html>
  1. render_template 函数

    • render_template 是 Flask 提供的一个函数,用于渲染 Jinja2 模板文件。

    • 会自动在 templates 文件夹中查找模板文件。

    • 通过关键字参数传递变量到模板中。

  2. 模板变量

    • 在模板中,使用 {``{ variable_name }} 来插入变量的值。

    • 例如,{``{ title }} 会插入 title 变量的值。

  3. 循环结构

    • 使用 {% for ... in ... %}{% endfor %} 来遍历列表。

    • messages 是一个列表,模板会为列表中的每个元素生成一个 <li> 标签。

在视图函数中渲染该模板

python 复制代码
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', 
                           title='Flask Template',
                           name='User',
                           messages=['Message 1', 'Message 2'])

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

3.2过滤器

常用内置过滤器

upper:将字符串转换为大写。

lower:将字符串转换为小写。

capitalize:将字符串的首字母大写。

title:将字符串的每个单词的首字母大写。

replace:替换字符串中的内容。

trim:去除字符串两端的空格。

default:如果变量为空或未定义,提供一个默认值。

join:将列表中的元素连接成一个字符串。

length:返回变量的长度。

sort:对列表进行排序。

<ul>

{% for message in messages|sort %}

<li>{{ message }}</li>

{% endfor %}

</ul>

自定义过滤器

假设用一个过滤器来反转字符串:

python 复制代码
@app.template_filter('reverse')
def reverse_filter(s):
    return s[::-1]

在模板中使用自定义过滤器:

html 复制代码
<body>
    <h1>Hello, {{ name|reverse }}!</h1>
</body>

3.3控制结构

1. 条件表达式(If-Else)

视图函数传递了一个变量 name 和一个布尔值 is_admin

python 复制代码
@app.route('/')
def index():
    return render_template('index.html', name='Alice', is_admin=True)
html 复制代码
    {% if is_admin %}
        <p>You are an administrator.</p>
    {% else %}
        <p>You are a regular user.</p>
    {% endif %}

2. 循环(For Loop)

模板中遍历列表或字典,并对每个元素进行处理。

视图函数传递了一个列表 messages

python 复制代码
@app.route('/')
def index():
    return render_template('index.html', messages=['Message 1', 'Message 2', 'Message 3'])

在模板中

html 复制代码
    <ul>
        {% for message in messages %}
            <li>{{ message }}</li>
        {% endfor %}
    </ul>

3. 循环控制(Loop Controls)

使用一些特殊的变量和控制语句来控制循环的行为

在循环中显示索引和每个元素

html 复制代码
<ul>
    {% for message in messages %}
        <li>{{ loop.index }}: {{ message }}</li>
    {% endfor %}
</ul>

loop.firstloop.last 来检查是否是第一个或最后一个元素

html 复制代码
<ul>
    {% for message in messages %}
        {% if loop.first %}
            <li class="first">{{ message }}</li>
        {% elif loop.last %}
            <li class="last">{{ message }}</li>
        {% else %}
            <li>{{ message }}</li>
        {% endif %}
    {% endfor %}
</ul>

4. 继承(Template Inheritance)

定义一个基础模板,然后在其他模板中继承和扩展它

一个基础模板 base.html

然后,可以创建一个继承自 base.html 的模板 index.html

html 复制代码
{% extends 'base.html' %}

{% block title %}Home Page{% endblock %}

{% block content %}
    <h1>Hello, {{ name }}!</h1>
    <p>Welcome to the home page.</p>
{% endblock %}

3.4静态文件

3.5URL生成

使用url_for()函数动态生成URL,避免硬编码

复制代码
url_for('home')

4、Flask-WTF表单处理

1. 安装 Flask-WTF

html 复制代码
pip install Flask-WTF -i https://pypi.mirrors.ustc.edu.cn/simple/

2. 创建表单类

用户注册表单,包含用户名、密码和提交按钮

python 复制代码
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=4, max=20)])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=35)])
    submit = SubmitField('Register')

3. 在视图函数中处理表单

实例化表单类,并根据请求方法处理表单数据

python 复制代码
from flask import Flask, render_template, redirect, url_for, flash
from forms import RegistrationForm

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        # 处理表单数据
        username = form.username.data
        password = form.password.data
        # 这里可以将数据保存到数据库
        flash(f'Account created for {username}!', 'success')
        return redirect(url_for('home'))
    return render_template('register.html', form=form)

@app.route('/')
def home():
    return 'Welcome to the Home Page'

if __name__ == '__main__':
    app.run(debug=True)
  • SECRET_KEY,秘密密钥,用于保护表单免受 CSRF 攻击。Flask-WTF 使用这个来生成表单的隐藏字段,确保表单提交的安全性
  • 使用 DataRequired 验证器确保字段不为空,使用 Length 验证器确保用户名长度在 4 到 20 个字符之间,使用 EqualTo 验证器确保输入与 password 字段相同
  • 使用 form.validate_on_submit() 检查表单是否通过验证
  • 使用 redirect 函数重定向到主页

4. 在模板中渲染表单

模板(templates/register.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Register</title>
</head>
<body>
    <h1>Register</h1>
    <form method="POST" action="">
        {{ form.hidden_tag() }}
        <div>
            {{ form.username.label }}<br>
            {{ form.username(size=20) }}<br>
            {% for error in form.username.errors %}
                <span style="color: red;">{{ error }}</span><br>
            {% endfor %}
        </div>
        <div>
            {{ form.password.label }}<br>
            {{ form.password(size=20) }}<br>
            {% for error in form.password.errors %}
                <span style="color: red;">{{ error }}</span><br>
            {% endfor %}
        </div>
        <div>
            {{ form.submit() }}
        </div>
    </form>
</body>
</html>

5. 表单验证

Flask-WTF 使用 WTForms 的验证器来验证表单数据

python 复制代码
from wtforms.validators import DataRequired, Length, Email, EqualTo

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=4, max=20)])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=35)])
    confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('Register')

6. 显示闪现消息

python 复制代码
from flask import flash

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        # 处理表单数据
        username = form.username.data
        flash(f'Account created for {username}!', 'success')
        return redirect(url_for('home'))
    return render_template('register.html', form=form)

在模板中显示闪现消息:

html 复制代码
{% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
        {% for category, message in messages %}
            <div class="alert alert-{{ category }}">{{ message }}</div>
        {% endfor %}
    {% endif %}
{% endwith %}

5、文件上传

创建 Flask 应用实例

python 复制代码
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['UPLOAD_FOLDER'] = 'static/uploads'
app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif'}
  • app.config['UPLOAD_FOLDER']:设置上传文件的保存路径。

  • app.config['ALLOWED_EXTENSIONS']:定义允许上传的文件类型。

定义允许的文件类型

python 复制代码
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']
  • 定义一个函数 allowed_file,用于检查文件名是否包含允许的扩展名。

  • filename.rsplit('.', 1)[1].lower():获取文件名的扩展名,并将其转换为小写。

  • 检查扩展名是否在 ALLOWED_EXTENSIONS 集合中。

创建表单类

python 复制代码
class UploadForm(FlaskForm):
    photo = FileField('Upload Photo', validators=[DataRequired()])
    submit = SubmitField('Upload')
  • 定义一个表单类 UploadForm,继承自 FlaskForm

  • photo 字段是一个文件上传字段,使用 DataRequired 验证器确保字段不为空。

  • submit 字段是一个提交按钮字段。

定义上传路由

python 复制代码
@app.route('/upload', methods=['GET', 'POST'])
def upload():
    form = UploadForm()
    if form.validate_on_submit():
        file = form.photo.data
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            flash('File successfully uploaded', 'success')
            return redirect(url_for('upload'))
        else:
            flash('Invalid file type', 'danger')
    return render_template('upload.html', form=form)

模板渲染

html 复制代码
<form method="POST" action="" enctype="multipart/form-data">
        {{ form.hidden_tag() }}
        <div>
            {{ form.photo.label }}<br>
            {{ form.photo() }}<br>
            {% for error in form.photo.errors %}
                <span style="color: red;">{{ error }}</span><br>
            {% endfor %}
        </div>
        <div>
            {{ form.submit() }}

6、数据库集成

安装Flask-SQLAlchemy

python 复制代码
pip install Flask-SQLAlchemy -i https://pypi.mirrors.ustc.edu.cn/simple/

在项目的根目录下创建 config.py 文件,配置数据库相关参数。这里将使用 SQLite 数据库,SQLAlchemy 也支持 MySQL、PostgreSQL 等其他数据库,只需修改相应的 URI。

python 复制代码
import os

basedir = os.path.abspath(os.path.dirname(__file__))

class Config:
    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False  # 关闭对象修改追踪系统

app.py 文件中初始化 Flask 应用和 SQLAlchemy

python 复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import Config

app = Flask(__name__)
app.config.from_object(Config)

db = SQLAlchemy(app)

# 导入模型
from models import User

@app.route('/')
def index():
    return "Hello, Flask with SQLAlchemy!"

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

也可以在主应用文件(如 app.py)中,初始化 Flask 应用和 SQLAlchemy

python 复制代码
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
  • SQLALCHEMY_DATABASE_URI:指定数据库的 URI。这里使用 SQLite 数据库,文件名为 site.db

  • SQLALCHEMY_TRACK_MODIFICATIONS:关闭 SQLAlchemy 的对象修改追踪系统,以减少内存使用。

定义模型类

models.py 文件中定义数据库模型。每个模型类继承自 db.Model,并使用 db.Column 定义表的列

用户模型

python 复制代码
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
    password = db.Column(db.String(60), nullable=False)
    posts = db.relationship('Post', backref='author', lazy=True)

    def __repr__(self):
        return f"User('{self.username}', '{self.email}', '{self.image_file}')"

1 db.Column

db.Column 用于定义表的列。常见的参数包括:

  • db.Integer:整数类型。

  • db.String(length) :字符串类型,length 是最大长度。

  • db.Text:长文本类型。

  • db.DateTime:日期和时间类型。

  • db.ForeignKey:外键,引用其他表的主键。

2 primary_key=True

指定该列为主键。每个表必须有一个主键,用于唯一标识表中的每一行。

3 unique=True

指定该列的值必须是唯一的。例如,用户名和电子邮件地址通常应该是唯一的。

4 nullable=False

指定该列不能为空。如果设置为 True,则该列可以为空。

5 default

指定该列的默认值。例如,image_file 列的默认值为 'default.jpg'

6 db.relationship

定义模型之间的关系。例如,UserPost 之间是一对多关系。db.relationship 用于定义这种关系,并提供方便的方法来访问相关对象。

  • backref :定义反向引用,允许从 Post 访问 User

  • lazy :指定加载相关对象的方式。True 表示在需要时加载,False 表示立即加载。

初始化数据库

在 Python shell 中运行以下命令,进入 Flask 项目环境

执行以下命令来创建数据库表

python 复制代码
from app import db
db.create_all()  # 这会根据模型创建所有的表

数据库迁移工具 Flask-Migrate

在项目开发过程中,随着需求的变化,我们可能需要修改数据库结构,比如添加或删除字段。为了方便管理数据库的迁移操作,可以使用 Flask-Migrate 来进行数据库迁移。

1. 安装 Flask-Migrate
python 复制代码
pip install Flask-Migrate -i https://pypi.mirrors.ustc.edu.cn/simple/
2. 初始化 Flask-Migrate

app.py 文件中初始化 Flask-Migrate:

python 复制代码
from flask_migrate import Migrate

app = Flask(__name__)
app.config.from_object(Config)

db = SQLAlchemy(app)
migrate = Migrate(app, db)

# 导入模型
from models import User
3. 创建迁移文件

初始化迁移环境

python 复制代码
flask db init

生成迁移文件

python 复制代码
flask db migrate -m "Initial migration"

执行迁移文件以应用更改

python 复制代码
flask db upgrade

基本 CRUD 操作

1 创建(Create)
python 复制代码
from app import db
from models import User

new_user = User(username='Kimi', email='kimi@example.com', password='password')
db.session.add(new_user)
db.session.commit()
2 读取(Read)

查询所有用户

python 复制代码
from models import User

users = User.query.all()
for user in users:
    print(user.username, user.email)

查询特定用户

python 复制代码
user = User.query.filter_by(username='Kimi').first()
print(user.email)
3 更新(Update)
python 复制代码
user = User.query.filter_by(username='Kimi').first()
if user:
    user.email = 'new_email@example.com'
    db.session.commit()
4 删除(Delete)
python 复制代码
user = User.query.filter_by(username='Kimi').first()
if user:
    db.session.delete(user)
    db.session.commit()

7.用户认证与授权

7.1 Flask-Login扩展

1. 安装 Flask-Login

python 复制代码
pip install Flask-Login -i https://pypi.mirrors.ustc.edu.cn/simple/

2.初始化 Flask 应用和扩展(app.py

python 复制代码
from flask import Flask, render_template, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from config import Config
from forms import RegistrationForm, LoginForm
from models import User

app = Flask(__name__)
app.config.from_object(Config)

db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

@app.route('/')
@login_required
def index():
    return "Hello, " + current_user.username + "!"

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data, password=form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Your account has been created!', 'success')
        return redirect(url_for('login'))
    return render_template('register.html', form=form)

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and user.password == form.password.data:
            login_user(user, remember=form.remember.data)
            return redirect(url_for('index'))
        else:
            flash('Login Unsuccessful. Please check email and password', 'danger')
    return render_template('login.html', form=form)

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.run(debug=True)
  • app = Flask(__name__):创建一个 Flask 应用实例。

  • app.config.from_object(Config):从 config.py 中加载配置。

  • db = SQLAlchemy(app):初始化 SQLAlchemy。

  • login_manager = LoginManager(app):初始化 Flask-Login。

  • login_manager.login_view = 'login':指定登录视图的名称。

  • @login_manager.user_loader:定义一个回调函数,用于加载用户对象。

  • @app.route('/'):定义主页路由,使用 @login_required 装饰器保护路由,确保只有认证用户才能访问。

  • @app.route('/register'):定义注册路由,处理用户注册逻辑。

  • @app.route('/login'):定义登录路由,处理用户登录逻辑。

  • @app.route('/logout'):定义登出路由,处理用户登出逻辑。

3.定义用户模型(models.py

python 复制代码
from flask_login import UserMixin

class User(UserMixin, db.Model):
  • UserMixin:提供默认的实现,用于 Flask-Login。

4.定义表单类(forms.py

python 复制代码
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from models import User

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=4, max=20)])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=35)])
    confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('Sign Up')

    def validate_username(self, username):
        user = User.query.filter_by(username=username.data).first()
        if user:
            raise ValidationError('That username is taken. Please choose a different one.')

    def validate_email(self, email):
        user = User.query.filter_by(email=email.data).first()
        if user:
            raise ValidationError('That email is taken. Please choose a different one.')

class LoginForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    remember = BooleanField('Remember Me')
    submit = SubmitField('Login')
  • RegistrationForm:注册表单,包含用户名、电子邮件、密码和确认密码字段。

  • LoginForm:登录表单,包含电子邮件和密码字段。

  • validate_usernamevalidate_email:自定义验证方法,确保用户名和电子邮件唯一。

5.创建模板文件

templates/login.html

7.2Flask-Bcrypt密码哈希

1. 安装 & 初始化

python 复制代码
pip install Flask-Bcrypt -i https://pypi.mirrors.ustc.edu.cn/simple/
python 复制代码
from flask_bcrypt import Bcrypt   # ① 导入
bcrypt = Bcrypt(app)              # ② 绑定到 app

2.密码哈希

python 复制代码
#生成密码哈希
def set_password(self, raw_password):
        self.password_hash = bcrypt.generate_password_hash(raw_password).decode('utf-8')

#验证密码
def check_password(self, raw_password):
        return bcrypt.check_password_hash(self.password_hash, raw_password)

3.应用场景代码

注册
python 复制代码
@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        # 先查重
        if User.query.filter((User.username == form.username.data) |
                             (User.email == form.email.data)).first():
            flash('用户名或邮箱已存在', 'warning')
            return redirect(url_for('register'))

        user = User(username=form.username.data,
                    email=form.email.data)
        user.set_password(form.password.data)   # ④ 哈希化
        db.session.add(user)
        db.session.commit()
        flash('注册成功,请登录', 'success')
        return redirect(url_for('login'))
    return render_template('register.html', form=form)
登录
python 复制代码
@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and user.check_password(form.password.data):  # ⑤ 校验
            login_user(user, remember=form.remember.data)
            next_page = request.args.get('next')
            return redirect(next_page) if next_page else redirect(url_for('index'))
        flash('邮箱或密码错误', 'danger')
    return render_template('login.html', form=form)
修改密码
python 复制代码
@app.route('/change_password', methods=['GET', 'POST'])
@login_required
def change_password():
    form = ChangePasswordForm()
    if form.validate_on_submit():
        if not current_user.check_password(form.old_password.data):
            flash('旧密码不正确', 'warning')
            return redirect(url_for('change_password'))
        current_user.set_password(form.new_password.data)  # ⑥ 重新哈希
        db.session.commit()
        flash('密码已更新,请重新登录', 'info')
        logout_user()
        return redirect(url_for('login'))
    return render_template('change_password.html', form=form)

7.3 Flask-Principal 基于角色的访问控制

Flask-Principal 是一个**轻量级权限(授权)**扩展,它与 Flask-Login 配合得最好:

Login 管"是谁",Principal 管"能干什么"。

1. 安装 & 蓝图结构

python 复制代码
pip install Flask-Principal -i https://pypi.mirrors.ustc.edu.cn/simple/

app/

├─ extensions.py # ← 所有扩展实例化

├─ models.py

├─ auth/ # 认证蓝本

└─ blog/ # 业务蓝本(带权限)

2. 初始化

python 复制代码
from flask_principal import Principal, Permission, RoleNeed

principal = Principal()          # ① 核心引擎

# ② 常用角色/权限先定义好
admin_permission = Permission(RoleNeed('admin'))
editor_permission = Permission(RoleNeed('editor'))

3. 用户模型(models.py

python 复制代码
from flask_login import UserMixin
from app import db
from flask_principal import identity_loaded, RoleNeed, UserNeed

class User(UserMixin, db.Model):
    id       = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True)
    role     = db.Column(db.String(20), default='user')   # 简单角色字段

# ④ 每次登录后自动把"角色"注入到身份
@identity_loaded.connect_via(db.Model)
def on_identity_loaded(sender, identity):
    identity.user = current_user
    # 基础身份
    identity.provides.add(UserNeed(current_user.id))
    # 角色身份
    if current_user.role:
        identity.provides.add(RoleNeed(current_user.role))

4. 登录动作

python 复制代码
from flask import Blueprint, redirect, url_for, flash
from flask_login import login_user, current_user
from app.extensions import principal
from app.models import User

auth = Blueprint('auth', __name__)

@auth.route('/login', methods=['POST'])
def login():
    user = User.query.filter_by(username=request.form['username']).first()
    if user and user.verify_password(request.form['password']):
        login_user(user)            # ⑤ Flask-Login 登录
        # ⑥ 手动触发 identity_changed(Principal 0.4+ 需手动)
        from flask_principal import identity_changed, Identity
        identity_changed.send(current_app._get_current_object(),
                              identity=Identity(user.id))
        flash('登录成功')
        return redirect(url_for('blog.index'))
    flash('用户名或密码错误')
    return redirect(url_for('auth.login'))

5. 视图层

A) 装饰器
python 复制代码
from flask import Blueprint
from app.extensions import admin_permission

blog = Blueprint('blog', __name__)

@blog.route('/admin/dashboard')
@admin_permission.require(http_exception=403)   # ⑦ 无权限直接 403
def admin_dashboard():
    return '只有 admin 能看到'
B) 模板内隐藏按钮
python 复制代码
{% if admin_permission.can() %}
    <a href="{{ url_for('blog.admin_dashboard') }}">后台管理</a>
{% endif %}

7.4Flask-Security

安装

python 复制代码
pip install Flask-Security-Too[common]  # 带邮件、Bcrypt、CLI 等常用依赖

先放着之后在学习

7.5REST API开发

指定文件路径创建python环境

复制代码
# 退出旧环境
deactivate

# 用 3.10 重新建虚拟环境
&"C:\Users\木南朋友\AppData\Local\Programs\Python\Python310\python.exe" -m venv venv310
venv310\Scripts\activate

# 装兼容版本
pip install -r requirements.txt -i https://pypi.org/simple/

先这样 2025年12月12日

相关推荐
西南胶带の池上桜2 小时前
支持pytorch的模型学习环境创建流程(长期更新)
人工智能·pytorch·学习
笨鸟先飞的橘猫2 小时前
RPC原理学习
网络协议·学习·rpc
BingoGo2 小时前
PHP 8.5 垃圾回收改进
后端·php
December3102 小时前
【少儿编程】Scratch vs Python:区别、学习顺序&实操指南
python·学习·青少年编程·scratch·少儿编程·编程学习
小鱼能吃糖2 小时前
微服务学习
学习
serve the people2 小时前
tensorflow 如何使用 tf.RaggedTensorSpec 来创建 RaggedTensor
人工智能·python·tensorflow
lingggggaaaa2 小时前
C2远控篇&C&C++&SC转换格式&UUID标识&MAC物理&IPv4地址&减少熵值
c语言·c++·学习·安全·web安全·网络安全·免杀对抗
larance2 小时前
使用setuptools 打包python 模块
开发语言·python
速易达网络2 小时前
Python全栈学习路径:从零基础到人工智能实战
python·flask