Flask-SQLAlchemy — 设计数据库模型
本章你将学会用 Flask-SQLAlchemy 定义数据模型,创建 SQLite 数据库表,并插入测试数据。
为什么要用 ORM?
直接写 SQL 语句操作数据库繁琐且容易出错。
ORM(对象关系映射) 让你用 Python 类来定义表结构,用 Python 方法操作数据。
Flask-SQLAlchemy 是 SQLAlchemy 的 Flask 集成版,封装了常见操作,配置更简单。
安装与配置
(venv) $ pip install flask-sqlalchemy
实例
# 文件路径:app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# SQLite 数据库文件路径(位于项目根目录)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
# 关闭修改追踪(节省内存,将来版本默认关闭)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 创建 db 实例,绑定到 app
db = SQLAlchemy(app)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# SQLite 数据库文件路径(位于项目根目录)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
# 关闭修改追踪(节省内存,将来版本默认关闭)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 创建 db 实例,绑定到 app
db = SQLAlchemy(app)
sqlite:///blog.db中的三个斜杠表示相对路径。SQLite 数据库就是一个文件,无需安装任何数据库软件,非常适合开发和测试。
定义模型:Post 和 Category
实例
# 文件路径:models.py
from datetime import datetime
from app import db
class Category(db.Model):
"""文章分类"""
__tablename__ = 'categories'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), unique=True, nullable=False)
slug = db.Column(db.String(50), unique=True, nullable=False)
# backref:在 Category 对象上可通过 .posts 反向获取其下所有文章
posts = db.relationship('Post', backref='category', lazy='dynamic')
def __repr__(self):
return f'<Category {self.name}>'
class Post(db.Model):
"""博客文章"""
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200), nullable=False)
slug = db.Column(db.String(200), unique=True, nullable=False)
summary = db.Column(db.Text, default='')
content = db.Column(db.Text, nullable=False)
# 外键:db.ForeignKey('表名.字段名')
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def __repr__(self):
return f'<Post {self.title}>'
from datetime import datetime
from app import db
class Category(db.Model):
"""文章分类"""
__tablename__ = 'categories'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), unique=True, nullable=False)
slug = db.Column(db.String(50), unique=True, nullable=False)
# backref:在 Category 对象上可通过 .posts 反向获取其下所有文章
posts = db.relationship('Post', backref='category', lazy='dynamic')
def __repr__(self):
return f'<Category {self.name}>'
class Post(db.Model):
"""博客文章"""
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200), nullable=False)
slug = db.Column(db.String(200), unique=True, nullable=False)
summary = db.Column(db.Text, default='')
content = db.Column(db.Text, nullable=False)
# 外键:db.ForeignKey('表名.字段名')
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def __repr__(self):
return f'<Post {self.title}>'
常用字段类型
| 字段类型 | 数据库类型 | 常用参数 |
|---|---|---|
| db.Integer | INTEGER | primary_key, autoincrement |
| db.String(N) | VARCHAR(N) | unique, nullable, default |
| db.Text | TEXT | default |
| db.DateTime | DATETIME | default, onupdate |
| db.Boolean | BOOLEAN | default |
| db.ForeignKey('表.字段') | FOREIGN KEY | — |
创建数据库表
与 Django 的 migrate 不同,Flask 需要手动初始化数据库表。
(venv) $ flask shell # 进入 Flask 交互式 Shell
实例
# 在 flask shell 中输入
from app import db
db.create_all() # 创建所有模型对应的数据库表
exit()
from app import db
db.create_all() # 创建所有模型对应的数据库表
exit()
执行后,项目根目录下会生成 blog.db 文件。
db.create_all()只在表不存在时才创建。如果修改了模型结构(如新增字段),它不会自动更新表。生产环境中应该用 Flask-Migrate(第五章)管理结构变更。
用 flask shell 插入测试数据
实例
# 在 flask shell 中输入
from app import db
from models import Category, Post
# 1. 创建分类
py_cat = Category(name='Python', slug='python')
css_cat = Category(name='CSS', slug='css')
flask_cat = Category(name='Flask', slug='flask')
db.session.add_all([py_cat, css_cat, flask_cat])
db.session.commit()
# 2. 创建文章
post1 = Post(
title='Flask 入门完全指南',
slug='flask-beginner-guide',
summary='从零开始学习 Flask,涵盖路由、模板、ORM 等核心概念。',
content='<h2>为什么学 Flask?</h2><p>Flask 是 Python 最灵活的 Web 微框架...</p>',
category=flask_cat
)
post2 = Post(
title='Python 协程详解',
slug='python-coroutine',
summary='一文搞懂 asyncio、协程、事件循环。',
content='<h2>什么是协程?</h2><p>协程是一种比线程更轻量的并发方案...</p>',
category=py_cat
)
post3 = Post(
title='CSS Grid 布局实战',
slug='css-grid-layout',
summary='用 CSS Grid 轻松实现复杂的响应式布局。',
content='<h2>Grid 入门</h2><p>Grid 是二维布局系统...</p>',
category=css_cat
)
db.session.add_all([post1, post2, post3])
db.session.commit()
# 3. 验证查询
print(Post.query.all())
print(Post.query.filter(Post.category_id == 1).all())
from app import db
from models import Category, Post
# 1. 创建分类
py_cat = Category(name='Python', slug='python')
css_cat = Category(name='CSS', slug='css')
flask_cat = Category(name='Flask', slug='flask')
db.session.add_all([py_cat, css_cat, flask_cat])
db.session.commit()
# 2. 创建文章
post1 = Post(
title='Flask 入门完全指南',
slug='flask-beginner-guide',
summary='从零开始学习 Flask,涵盖路由、模板、ORM 等核心概念。',
content='<h2>为什么学 Flask?</h2><p>Flask 是 Python 最灵活的 Web 微框架...</p>',
category=flask_cat
)
post2 = Post(
title='Python 协程详解',
slug='python-coroutine',
summary='一文搞懂 asyncio、协程、事件循环。',
content='<h2>什么是协程?</h2><p>协程是一种比线程更轻量的并发方案...</p>',
category=py_cat
)
post3 = Post(
title='CSS Grid 布局实战',
slug='css-grid-layout',
summary='用 CSS Grid 轻松实现复杂的响应式布局。',
content='<h2>Grid 入门</h2><p>Grid 是二维布局系统...</p>',
category=css_cat
)
db.session.add_all([post1, post2, post3])
db.session.commit()
# 3. 验证查询
print(Post.query.all())
print(Post.query.filter(Post.category_id == 1).all())
Flask-SQLAlchemy 基础查询
| 方法 | 等价 SQL | 返回值 |
|---|---|---|
| Post.query.all() | SELECT * FROM posts | 列表 |
| Post.query.get(1) | WHERE id = 1 | 单个对象或 None |
| Post.query.get_or_404(1) | WHERE id = 1 | 单个对象或自动返回 404 |
| Post.query.filter_by(category_id=1).all() | WHERE category_id=1 | 列表 |
| Post.query.filter(Post.title.ilike('%flask%')).all() | WHERE title LIKE '%flask%' | 列表 |
| Post.query.order_by(Post.created_at.desc()).all() | ORDER BY created_at DESC | 列表 |
本章小结
本章你掌握了 Flask-SQLAlchemy 的完整流程:安装并配置 SQLALCHEMY_DATABASE_URI、db.Model 定义模型(字段类型/外键/relationship)、db.create_all() 初始化建表、flask shell 中插入与查询数据。
至此,文章和分类的数据结构已在 SQLite 数据库中建立。
