python SQLAlchemy(ORM)操作数据库详解!!!

初识SQLAlchemy

特点:

SQLAlchemy 是一个功能强大的 Python SQL 工具包和对象关系(ORM)映射框架,旨在提供高效、灵活且便于扩展的数据库交互解决方案。它支持多种数据库,并通过其核心(Core)和 ORM 两个层次为开发者提供不同的抽象级别

  • 使用python进行编写
  • 一个sql工具包
  • 一个orm框架
  • 支持常见数据库:sqlserver、mysql、oracle、postgresql、sqllite

下述所展示的操作都以MySQL数据库为例!!!

安装

pip install sqlalchemy

  • 如果要使用sqlalchemy操作mysql数据库,还需要安装mysqlclient:
  • pip install mysqlclient

流程介绍

创建engine

Engine 是 SQLAlchemy 与数据库之间的接口,负责管理数据库连接和执行

python 复制代码
from sqlalchemy import create_engine

engine = create_engine("mysql+pymysql://user:password@host:port/mydatabase", echo=True)

参数详解:

  • user:数据库用户
  • password:数据库密码
  • host:数据库地址,本地默认为localhost或127.0.0.1
  • port:数据库端口,默认为3306
  • mydatabase:数据库名称
  • echo:是否展示详细数据库操作,True为展示,默认为False

建立连接

python 复制代码
connection=engine.connect()

查询数据

原始sql查询语句

python 复制代码
from sqlalchemy import create_engine, text

engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)

# 创建一个连接
conn = engine.connect()

# 创建一个查询
query = text("SELECT * FROM users")

# 执行查询
result = conn.execute(query)

# 关闭连接
conn.close()

# 销毁引擎
engine.dispose() 

初始版创建表结构

概念信息:

  • MetaData: 是 SQLAlchemy 用于存储关于数据库结构信息的对象。它包含了所有表、列、约束等的定义
  • TableColumn 是定义数据库表和其列的基础组件

示例代码:

python 复制代码
from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    Integer,
    String,
    Date,
)

# 创建一个引擎
engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)

# 创建一个元数据
metadata = MetaData()

# 创建一个表
table = Table(
    # 表名
    "users",
    # 元数据(表的描述)
    metadata,
    # 列
    Column("id", Integer, primary_key=True),
    Column("name", String(255), nullable=False, unique=True),
    Column("birthday", Date, nullable=False),
)

# 创建表
metadata.create_all(engine)

Column 属性详解

  • 类型:如 Integer, String, Boolean, DateTime 等,定义列的数据类型。
  • 主键(primary_key=True):指定该列为主键。
  • 索引(index=True):为该列创建索引,提高查询性能。
  • 可空(nullable=False/True):指定该列是否允许为空。
  • 默认值(default):为该列设置默认值。
  • 自动更新时间(onupdate):在每次更新时自动设置列的值

插入数据(INSERT)

python 复制代码
# 新增数据
insert_data = table.insert().values(name="张三", birthday="2021-01-01")

# 执行插入
with engine.connect() as conn:
    conn.execute(insert_data)
    # 提交事务
    conn.commit()

table.insert():数据库的插入insert对象

批量插入

python 复制代码
# 批量插入
insert_data = table.insert().values(
    [
        {"name": "李四", "birthday": "2021-01-02"},
        {"name": "王五", "birthday": "2021-01-03"},
    ]
)
# 执行插入

with engine.connect() as conn:
    conn.execute(insert_data)
    # 提交事务
    conn.commit()
python 复制代码
# 批量插入
insert_data = table.insert()
# 执行插入
with engine.connect() as conn:
    conn.execute(
        insert_data,
        [
            {"name": "赵六", "birthday": "2021-01-04"},
            {"name": "孙七", "birthday": "2021-01-05"},
        ],
    )
    # 提交事务
    conn.commit()

查询数据(SELECT)

python 复制代码
with engine.connect() as connect:
    query = user_table.select()
    query_set = connect.execute(query)

    # query_set 迭代器
    for row in query_set:
        print(row)
        print(row.name)

提取数据

python 复制代码
# 提取所有数据
result = query_set.fetchall()
# 提取一条数据
res_one = query_set.fetchone()

条件查询

python 复制代码
with engine.connect() as connect:
    query = user_table.select().where(user_table.c.birthday > "2021-01-04")
        query_set = connect.execute(query)
    result = query_set.fetchall()
    print(result)

复杂查询:

python 复制代码
with engine.connect() as connect:
    query = (
        user_table.select()
        .where(user_table.c.birthday > "2021-01-01")
        .where(user_table.c.name == "李四")
    )
    query = user_table.select().where(
        or_(
            user_table.c.name == "赵六",
            and_(user_table.c.birthday > "2021-01-01", user_table.c.id < 7),
        )
    )
    query_set = connect.execute(query)

    result = query_set.fetchall()
    print(result)

更新数据(UPDATE)

python 复制代码
with engine.connect() as connect:
    update_query = user_table.update().values(birthday="2000-06-09")
    update_query = (
        user_table.update()
        .values(birthday="2000-06-25")
        .where(user_table.c.name == "张三")
    )
    connect.execute(update_query)
    connect.commit()

删除数据(DELETE)

python 复制代码
with engine.connect() as connect:
    delete_query = user_table.delete()
    delete_query = user_table.delete().where(user_table.c.name == "孙七")
    connect.execute(delete_query)
    connect.commit()

关联表的定义

python 复制代码
from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    Integer,
    String,
    Date,
    ForeignKey,
)

# 创建一个引擎
engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)

# 创建一个元数据
metadata = MetaData()

# 部门
department = Table(
    "department",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String(255), nullable=False, unique=Table),
)

# 部门
employee = Table(
    "employee",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String(255), nullable=False),
    Column("department_id", Integer, ForeignKey("department.id"), nullable=False),
    Column("birthday", Date, nullable=False),
) 
metadata.create_all(engine)

插入数据

python 复制代码
from db_init import engine, employee, department
with engine.connect() as connect:
    connect.execute(department.insert(), [{"name": "HR"}, {"name": "IT"}])
    connect.execute(
        employee.insert(),
        [
            {"name": "aaa", "department_id": 1, "birthday": "2000-06-09"},
            {"name": "bbb", "department_id": 1, "birthday": "2000-06-10"},
            {"name": "ccc", "department_id": 2, "birthday": "2000-06-11"},
            {"name": "ddd", "department_id": 2, "birthday": "2000-06-12"},
        ],
    )
    connect.commit()

查询数据

python 复制代码
from db_init import engine, employee, department
from sqlalchemy import select

with engine.connect() as connect:
    join_table = employee.join(department, employee.c.department_id == department.c.id)
    query = select(join_table).where(department.c.name == "IT")
    query = select(employee).select_from(join_table).where(department.c.name == "IT")
    print(connect.execute(query).fetchall())

映射类的定义

生成数据库表

python 复制代码
from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    Integer,
    String,
    Date,
    ForeignKey,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 创建一个引擎
engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)

Base = declarative_base()


class Person(Base):

    __tablename__ = "person"

    id = Column(Integer, primary_key=True)
    name = Column(String(128), unique=True, nullable=False)
    birthday = Column(Date, nullable=False)
    address = Column(String(255), nullable=True)


Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

插入数据

单条数据

python 复制代码
from db_init import Session, Person

session = Session()

per = Person(name="aaa", birthday="2000-06-09", address="北疆")

session.add(per)

session.commit()

多条数据

python 复制代码
from db_init import Session, Person

session = Session()

# per = Person(name="aaa", birthday="2000-06-09", address="北疆")

per = [
    Person(name="bbb", birthday="2000-06-10", address="东疆"),
    Person(name="ccc", birthday="2000-06-11", address="南疆"),
]

session.add_all(per)

session.commit()

映射类的查询与修改

查询:

python 复制代码
from db_init import Session, Person

session = Session()
result = session.query(Person).all()
result = session.query(Person).filter(Person.address == "南疆")

修改:

python 复制代码
from db_init import Session, Person

session = Session()

# 第一种
per = session.query(Person).filter(Person.id == 1).first()
per.name = "ddd"
# 第二种
per = session.query(Person).filter(Person.id == 2).update({"name": "www"})

session.commit()

优化映射方式

前提:sqlalchemy版本需要大于2.0

python 复制代码
from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    Integer,
    String,
    Date,
    ForeignKey,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column

# 创建一个引擎
engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)

Base = declarative_base()


class Customer(Base):

    __tablename__ = "customer"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(20))
    birthday: Mapped[Date] = mapped_column(Date)


Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)

session = Session()

优化:

python 复制代码
from datetime import datetime
from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    Integer,
    String,
    Date,
    ForeignKey,
    DateTime,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column
from typing_extensions import Annotated

# 创建一个引擎
engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)

Base = declarative_base()

id_pk = Annotated[int, mapped_column(primary_key=True)]
require_name = Annotated[str, mapped_column(String(20), nullable=False)]
create_time = Annotated[datetime, mapped_column(DateTime, default=datetime.now)]


class Customer(Base):

    __tablename__ = "customer"

    id: Mapped[id_pk]
    name: Mapped[require_name]
    birthday: Mapped[Date] = mapped_column(Date)
    create_time: Mapped[create_time]


Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)

session = Session()

一对多ORM操作

初始化表:

python 复制代码
from datetime import datetime
from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    Integer,
    String,
    Date,
    ForeignKey,
    DateTime,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column, relationship
from typing_extensions import Annotated
from typing import List

# 创建一个引擎
engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)

Base = declarative_base()

id_pk = Annotated[int, mapped_column(primary_key=True)]
require_name = Annotated[str, mapped_column(String(20), nullable=False)]
create_time = Annotated[datetime, mapped_column(DateTime, default=datetime.now)]


class Department(Base):
    __tablename__ = "department"

    id: Mapped[id_pk]
    name: Mapped[require_name]
    create_time: Mapped[create_time]
    # 反向关联 动态的向employee表中添加department属性
    employees: Mapped[List["Employee"]] = relationship(
        lazy="select", back_populates="department"
    )

    def __repr__(self):
        return f"<Department(id={self.id}, name={self.name}, create_time={self.create_time})>"


class Employee(Base):
    __tablename__ = "employee"

    id: Mapped[id_pk]
    name: Mapped[require_name]
    department_id: Mapped[int] = mapped_column(ForeignKey("department.id"))
    create_time: Mapped[create_time]
    birthday: Mapped[Date] = mapped_column(Date, nullable=True)

    # 反向关联 动态的向department表中添加employees属性
    department: Mapped[Department] = relationship(
        lazy="select", back_populates="employees"
    )

    def __repr__(self):
        return f"<Employee(id={self.id}, name={self.name}, department_id={self.department_id}, create_time={self.create_time}, birthday={self.birthday})>"


Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)

session = Session()

新增及查询:

python 复制代码
from many_db_init import session, Department, Employee


def insert_data():
    dep1 = Department(name="开发部")
    dep2 = Department(name="销售部")
    emp1 = Employee(name="张三", department=dep1)
    emp2 = Employee(name="李四", department=dep2)

    session.add(emp1)
    session.add(emp2)
    session.commit()


def select_data():
    # 查询部门员工
    departments = session.query(Department).filter(Department.id == 3).first()
    print(departments.employees)

    # 查询员工部门
    employees = session.query(Employee).filter(Employee.name == "张三").first()
    print(employees.department)  # 反向关联


if __name__ == "__main__":
    insert_data()
    select_data()

多对多ORM操作

初始化数据库表:

python 复制代码
from datetime import datetime
from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    Integer,
    String,
    Date,
    ForeignKey,
    DateTime,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column, relationship
from typing_extensions import Annotated
from typing import List

# 创建一个引擎
engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)

Base = declarative_base()

id_pk = Annotated[int, mapped_column(primary_key=True)]
require_name = Annotated[str, mapped_column(String(20), nullable=False)]
create_time = Annotated[datetime, mapped_column(DateTime, default=datetime.now)]

assocaiation_table = Table(
    "user_role",
    Base.metadata,
    Column("user_id", Integer, ForeignKey("users.id"), primary_key=True),
    Column("role_id", Integer, ForeignKey("roles.id"), primary_key=True),
)


class User(Base):
    __tablename__ = "users"

    id: Mapped[id_pk]
    name: Mapped[require_name]
    create_time: Mapped[create_time]
    roles: Mapped[List["Role"]] = relationship(
        secondary=assocaiation_table, lazy=False, back_populates="users"
    )

    def __repr__(self):
        return f"<User(id={self.id}, name={self.name}, create_time={self.create_time})>"


class Role(Base):
    __tablename__ = "roles"

    id: Mapped[id_pk]
    name: Mapped[require_name]
    create_time: Mapped[create_time]
    users: Mapped[List["User"]] = relationship(
        secondary=assocaiation_table, lazy=False, back_populates="roles"
    )

    def __repr__(self):
        return f"<User(id={self.id}, name={self.name}, create_time={self.create_time})>"


Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)

session = Session()

新增数据及查询数据

python 复制代码
from many_to_namy_init import User, Role, session


def insert_records():
    role1 = Role(name="admin")
    role2 = Role(name="operate")
    user1 = User(name="张三")
    user2 = User(name="李四")
    user3 = User(name="王五")

    user1.roles.append(role1)
    user1.roles.append(role2)
    user2.roles.append(role2)
    user3.roles.append(role1)

    session.add_all([user1, user2, user3])

    session.commit()


def select_records():
    user = session.query(User).filter(User.name == "张三").first()
    print(user)
    print(user.roles)

    role = session.query(Role).filter(Role.name == "admin").first()
    print(role)
    print(role.users)


if __name__ == "__main__":
    # insert_records()
    select_records()

基于ORM查询

以下述数据表举例:

python 复制代码
from datetime import datetime, date
from sqlalchemy import (
    create_engine,
    MetaData,
    Table,
    Column,
    Integer,
    String,
    Date,
    ForeignKey,
    DateTime,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column, relationship
from typing_extensions import Annotated


# 创建一个引擎
engine = create_engine("mysql+pymysql://root:root@localhost:3306/orm_study", echo=True)


Base = declarative_base()

id_pk = Annotated[int, mapped_column(primary_key=True)]
require_name = Annotated[str, mapped_column(String(20), nullable=False)]
create_time = Annotated[datetime, mapped_column(DateTime, default=datetime.now)]
birthday = Annotated[date, mapped_column(Date, nullable=False)]


# 部门
class Department(Base):
    __tablename__ = "department"
    id: Mapped[id_pk]
    name: Mapped[require_name]
    create_time: Mapped[create_time]

    def __repr__(self):
        return f"Department(id={self.id}, name={self.name}, create_time={self.create_time})"


# 员工
class Employee(Base):
    __tablename__ = "employee"
    id: Mapped[id_pk]
    name: Mapped[require_name]
    department_id: Mapped[int]
    birthday: Mapped[birthday]
    create_time: Mapped[create_time]

    department: Mapped[Department] = relationship(
        Department, back_populates="employees"
    )

    def __repr__(self):
        return f"Employee(id={self.id}, name={self.name}, department_id={self.department_id}, birthday={self.birthday}, create_time={self.create_time})"


Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)

session = Session()

查询所有部门:

python 复制代码
def select_one():
    # 查询所有部门 先生成一个查询对象
    query = select(Department).order_by(Department.name.desc())
    # 执行查询
    result = session.execute(query)
    # 遍历结果
    for department in result:
        print(department)

查询员工和员工对应的部门(使用别名)

python 复制代码
def select_one_by_id():
    query = select(Department, Employee).join(Employee.department)
    result = session.execute(query)
    for department in result:
        print(department)


# 别名
def select_one_by_alias():
    employee_alias = aliased(Employee, name="employee_alias")
    department_alias = aliased(Department, name="department_alias")
    query = select(department_alias, employee_alias).join(
        employee_alias.department.of_type(department_alias)
    )
    result = session.execute(query)
    for department in result:
        print(department)

查询多个类中的部分字段(针对单个字段取别名)

python 复制代码
def select_fields():
    query = select(
        Department.name.label("department_name"),
        Employee.name.label("employee_name"),
    ).join(Employee.department)
    result = session.execute(query)
    for department in result:
        print(department.department_name, department.employee_name)
        
        
def select_fields01():
    query = select(
        Department.name.label("department_name"),
        Employee.name.label("employee_name"),
    ).join_from(Employee, Department)
    result = session.execute(query)
    for department in result:
        print(department.department_name, department.employee_name)
相关推荐
失去妙妙屋的米奇4 小时前
matplotlib数据展示
开发语言·图像处理·python·计算机视觉·matplotlib
搞不懂语言的程序员4 小时前
备忘录模式深度解析与实战案例
数据库·python·备忘录模式
爱的叹息5 小时前
关于 JDK 中的 jce.jar 的详解,以及与之功能类似的主流加解密工具的详细对比分析
java·python·jar
Lhuu(重开版5 小时前
2025第十六届蓝桥杯PythonB组部分题解
python
程丞Q香5 小时前
python——学生管理系统
开发语言·python·pycharm
dragon_perfect6 小时前
ubuntu22.04上设定Service程序自启动,自动运行Conda环境下的Python脚本(亲测)
开发语言·人工智能·python·conda
明月看潮生6 小时前
青少年编程与数学 02-016 Python数据结构与算法 15课题、字符串匹配
python·算法·青少年编程·编程与数学
凡人的AI工具箱7 小时前
PyTorch深度学习框架60天进阶学习计划 - 第41天:生成对抗网络进阶(一)
人工智能·pytorch·python·深度学习·学习·生成对抗网络
是大嘟嘟呀7 小时前
爬虫框架 - Coocan
python·系统架构·网络爬虫