简介
本博客借鉴于https://www.yuque.com/hynever/rd5ufc?#,可搭配食用
在python中,我们常使用ORM(Object Relationship Mapping)框架来操作数据库,然后在众多ORM框架中,最主流的是SQLALchemy,它经常与fastapi搭配食用,因为都支持异步。
安装
写此篇时,我是看fastapi+sqlalchemy+vue的教程,所以主要记录的是异步版本的sqlalchemy(见下),安装之后还得安装驱动,安装时注意也要安装异步的,详细安装步骤临时搜即可。
1
| $ pip install "sqlalchemy[asyncio]"
|
注意初始化项目时,选择fastapi框架。每个框架的初始化都不同,每次从零自己新建文件夹有点蠢。
创建连接
1、配置连接参数
使用SQLAlchemy连接数据库,是通过设置一个固定格式的字符串来实现的。mysql+aiomysql为例,那么其连接格式如下:(一般放在settings.py文件中)
1
| DB_URI = "mysql+aiomysql://用户名:密码@主机名:端口号/数据库名称?charset=utf8mb4"
|
示例(本地):
1
| DB_URI = "mysql+aiomysql://root:root@127.0.0.1:3306/book_db?charset=utf8mb4"
|
2、创建Engine对象(管理连接用)
SQLAlchemy中的Engine对象,它负责管理数据库连接的创建(并不直接操作数据库)、连接池的维护、SQL语句的翻译等。Engine对象在整个程序中只能有一个。创建Engine对象代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine( DB_URI, echo=True, pool_size=10, max_overflow=20, pool_timeout=10, pool_recycle=3600, pool_pre_ping=True, )
|
3、创建会话工厂
使用sqlalchemy.orm.sessionmaker类来创建会话工厂,这个会话工厂实际上就是Session或者它的子类,以后如果要操作数据库,那么就需要创建一个会话工厂的对象(即:Session类的对象),来完成相关操作。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.asyncio import AsyncSession
AsyncSessionFactory = sessionmaker( bind=engine, class_=AsyncSession, autoflush=True, expire_on_commit=False )
|
创建模型
1、定义Base类
Base类是所有ORM Model类的父类,一个ORM Model类对应数据库中的一张表,ORM Model中的一个Column类属性对应数据库表中的一个字段。Base类的生成可以使用sqlalchemy.ext.declarative.declarative_base函数来实现,也可以继承sqlalchemy.MetaData类,实现自己的子类,并在子类中编写约束规范。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from sqlalchemy.orm import DeclarativeBase from sqlalchemy import MetaData
class Base(DeclarativeBase): metadata = MetaData(naming_convention={ "ix": 'ix_%(column_0_label)s', "uq": "uq_%(table_name)s_%(column_0_name)s", "ck": "ck_%(table_name)s_%(constraint_name)s", "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", "pk": "pk_%(table_name)s" })
|
2、创建ORM模型
这里我们以创建一个User模型为例来说明模型的创建(每一个ORM模型对应数据库中的一张表)
1 2 3 4 5 6 7 8 9 10 11
| from typing import Optional from sqlalchemy import Integer, String, select from sqlalchemy.orm import Mapped, mapped_column
class User(Base): __tablename__ = 'user'
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) email: Mapped[str] = mapped_column(String(100),unique=True,index=True) username: Mapped[str] = mapped_column(String(100)) password: Mapped[str] = mapped_column(String(200))
|
3、模型关系(各表关系)
这里我们使用外键来实现一对一、一对多和多对多,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship from sqlalchemy import Integer, String, Text, ForeignKey
class User(Base): __tablename__ = 'user' id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) email: Mapped[str] = mapped_column(String(100),unique=True,index=True) username: Mapped[str] = mapped_column(String(100)) password: Mapped[str] = mapped_column(String(200))
user_extension: Mapped["UserExtension"] = relationship(back_populates="user", uselist=False) articles: Mapped['Article'] = relationship(back_populates="author")
class UserExtension(Base): __tablename__ = 'user_extension' id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) university: Mapped[str] = mapped_column(String(100)) user_id: Mapped[int] = mapped_column(Integer, ForeignKey("user.id")) user: Mapped["User"] = relationship(back_populates="user_extension")
class Tag(Base): __tablename__ = 'tag' id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) name: Mapped[str] = mapped_column(String(100), unique=True) articles: Mapped[list["Article"]] = relationship("Article", secondary="article_tag", back_populates='tags', lazy='dynamic')
class Article(Base): __tablename__ = 'article' id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) title: Mapped[str] = mapped_column(String(100)) content: Mapped[str] = mapped_column(Text) author_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id')) author: Mapped["User"] = relationship("User", back_populates='articles') tags: Mapped[list["Tag"]] = relationship("Tag", secondary="article_tag", back_populates='articles', lazy='dynamic')
class ArticleTag(Base): __tablename__ = "article_tag" article_id: Mapped[int] = mapped_column(Integer, ForeignKey("article.id"), primary_key=True) tag_id: Mapped[int] = mapped_column(Integer, ForeignKey("tag.id"), primary_key=True)
|
看代码的话有点复杂,感觉很多时候也没必要理解各个表的关系,vibecoding时应该更不用管
模型迁移
模型定义好后,要将模型映射到数据库中生成表,或者是以后模型上的字段名、字段类型等发生改变了,可以非常方便的使用alembic来进行迁移。
迁移用的包
1
| $ pip install alembic==1.13.2
|
吐槽:怎么干个啥动作都要安装一个包,就这玩意不能直接集成到sqlalchemy中吗?
用法:和git差不多(也支持版本回退),得先创建迁移仓库,然后生成迁移脚本(效果图如下),具体的问AI

后续工作
上面讲的是数据库模块细节,在项目中,它还是要与其它模块对接的。这个过程中,session作为中间人,在python端的main函数等模块和数据库之前起桥梁作用。
感言
说实话专门拿一个框架来管理数据库还是有点麻烦,感觉不如直接去数据库中执行sql语句来的方便。但是在vibecoding中AI真的会告诉我应该怎么执行sql语句吗,在这个角度来看,应该还是用高级语言来写数据库方便点,也许是初学的原因,感觉有点复杂,或许以后可以试试其它轻量级的数据库框架?pysql?sqllite?
本作品由 Hafsun 于 2026-04-18 12:47:00 发布
除特别声明外,本站作品均采用
CC BY-NC-SA 4.0 许可协议,转载请注明来自
欢迎回家