目录
[3、Jinja2 模板](#3、Jinja2 模板)
[1. 条件表达式(If-Else)](#1. 条件表达式(If-Else))
[2. 循环(For Loop)](#2. 循环(For Loop))
[3. 循环控制(Loop Controls)](#3. 循环控制(Loop Controls))
[4. 继承(Template Inheritance)](#4. 继承(Template Inheritance))
[1. 安装 Flask-WTF](#1. 安装 Flask-WTF)
[2. 创建表单类](#2. 创建表单类)
[3. 在视图函数中处理表单](#3. 在视图函数中处理表单)
[4. 在模板中渲染表单](#4. 在模板中渲染表单)
[5. 表单验证](#5. 表单验证)
[6. 显示闪现消息](#6. 显示闪现消息)
[创建 Flask 应用实例](#创建 Flask 应用实例)
[数据库迁移工具 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.1 Flask-Login扩展](#7.1 Flask-Login扩展)
[1. 安装 Flask-Login](#1. 安装 Flask-Login)
[2.初始化 Flask 应用和扩展(app.py)](#2.初始化 Flask 应用和扩展(app.py))
[1. 安装 & 初始化](#1. 安装 & 初始化)
[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.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>
render_template函数:
render_template是 Flask 提供的一个函数,用于渲染 Jinja2 模板文件。会自动在
templates文件夹中查找模板文件。通过关键字参数传递变量到模板中。
模板变量:
在模板中,使用
{``{ variable_name }}来插入变量的值。例如,
{``{ title }}会插入title变量的值。循环结构:
使用
{% 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.first 和 loop.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定义模型之间的关系。例如,
User和Post之间是一对多关系。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_username和validate_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日