Bootstrap

Sqlalchemy学习

连接数据库

import sqlalchemy


database_url = 'mysql+pymysql://username:password@localhost:3306/database'
# pymysql 需要下载包 pip install pymysql
engine = sqlalchemy.create_engine(database_url)  # 创建了一个数据库引擎

# 测试连接
try:
    with engine.connect() as connection:
        print("数据库连接成功")
except Exception as e:
    print(f"连接失败: {e}")

单表操作

import sqlalchemy
from sqlalchemy.orm import sessionmaker
# declarative_base 是 SQLAlchemy 的基类,用于定义数据模型
from sqlalchemy.orm import declarative_base

from sqlalchemy import Column, Integer, String

database_url = 'mysql+pymysql://username:password@localhost:3306/database'
engine = sqlalchemy.create_engine(database_url)  # 创建了一个数据库引擎
# 测试连接
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) # 创建了一个会话类,用于与数据库交互
Base = declarative_base()


class User(Base):
    __tablename__ = "users"
    # __tablename__ 指定了表名
    # Column 定义了表中的列及其类型
    id = Column(Integer, primary_key=True, index=True)
    # id,Integer 类型,primary_key为主键
    name = Column(String(255), index=True)
    # String 字符类型,255最大长度,类似于django ORM的 CharField,max_length=255
    # index=True 表示为该列创建索引,以便在按 name 列进行查询时提高性能
    # unique 唯一值,唯一索引
    email = Column(String(255), unique=True, index=True)


# Base.metadata.create_all(bind=engine) 这句话表示创建所有的表
Base.metadata.create_all(bind=engine)

当我们运行这个py文件,他就会执行create_all 这个函数,那么就会把我们的user这张表创建在库中

新增数据

from main import SessionLocal
from moudel import User

db = SessionLocal()
# 创建一个新的 User 对象,并初始化 name 和 email 属性
new_user = User(name='zh', email='[email protected]')
# 将新创建的 User 对象添加到当前的数据库会话中。这意味着在提交事务时,这个对象将被插入到数据库中
db.add(new_user)
# 提交当前的数据库会话,将所有在会话中进行的更改(包括插入新用户)持久化到数据库中
db.commit()
# 刷新 new_user 对象,使其包含最新的数据库状态。这通常用于确保对象的属性(如自动生成的 id)是最新的
db.refresh(new_user)

查询数据

查询单个
usr_a = db.query(User).filter(User.email == '').first()
print(usr_a.id)
print(usr_a.name)
print(usr_a.email)
查询所有
user_all = db.query(User).all()
print(user_all, type(user_all))  # 类型是 <class 'list'> ,可以for循环拿
for user in user_all:
    print(user.id)

修改数据

usr_a = db.query(User).filter(User.email == '').first()
usr_a.name = '彭于晏'
# 这个commit 可以理解为django的save()方法,只是django中有模型类对象.save(),sqlalchemy中用的会话
# 对象
db.commit()
print(usr_a.name)  # 彭于晏

删除数据

usr_a = db.query(User).filter(User.email == '').first()
db.delete(usr_a)
db.commit()

and与or查询

可以直接在 filter 方法中使用多个条件,用逗号分隔,这相当于使用 and 逻辑

usr_a = db.query(User).filter(User.email == '', User.name == '').first()
print(usr_a.id)

我们导入_or 来进行查询

from sqlalchemy import or_

usr_a = db.query(User).filter(or_(User.name == '', User.name == '')).all()
print(usr_a, type(usr_a))  # 这个类型还是list,结果几个都是放在列表中

关于查询我们需要知道,如果我们没有执行.all()或者.first(),那么只会创建一个查询对象,也就是我们的SQL语句,点.all()或者.first()才会真正的执行查询语句

usr_a = db.query(User).filter(or_(User.name == '', User.name == '')) 返回的是一个 Query 对象,而不是实际的查询结果。Query 对象代表了一个待执行的查询,直到你调用 all()first()one() 等方法才会实际执行查询并返回结果

 多表操作

一对一表创建

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship


class UserInfo(Base):
    __tablename__ = "user_info"
    id = Column(Integer, primary_key=True)
    address = Column(String(255), index=True)
    user = relationship("User", back_populates="userinfo")
# relationship("User", back_populates="userinfo",uselist=False):定义了一个关系属性 user,表示 UserInfo 和 User 之间的一对一关系
# back_populates="userinfo":指定反向引用的属性名称,即在 User 模型中定义的 userinfo 属性
# uselist=False:表示这是一个一对一关系,而不是一对多关系。默认情况下,relationship 会创建一个列表,uselist=False 使它返回单个对象

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(255), index=True)
    email = Column(String(255), unique=True, index=True)
    userinfo_id = Column(Integer, ForeignKey('user_info.id'), unique=True)
    userinfo = relationship("UserInfo", back_populates="user")
# Column(Integer, ForeignKey('user_info.id'), unique=True):定义了一个整数类型的列 #userinfo_id,并将其设置为外键(foreign key),引用 user_info 表的 id 列。同时,unique=True 确保# 每个 User 对象只能有一个 UserInfo 对象
# userinfo:relationship("UserInfo", back_populates="user"):定义了一个关系属性 userinfo,
# 表示 User 和 UserInfo 之间的一对一关系。
# "UserInfo":指定关系的目标模型。
# back_populates="user":指定反向引用的属性名称,即在 UserInfo 模型中定义的 user 属性

relationship:用于定义关系

userinfo_id:是一个外键,指向 UseInfo表的 id 字段

userinfo:是一个关系属性,类型为 UserInfo,并通过 back_populates 参数指定了反向引用的属性名称为 user

一对一创建数据

# 一对一创建数据,先创建没有外键字段的表
user_info = UserInfo(address='上海')
user = User(name='', email='', userinfo=user_info)
db.add(user)
db.commit()
db.refresh(user)

一对一跨表查询

使用 join 进行跨表查询

# 查询所有用户的姓名和地址
results = db.query(User.name, UserInfo.address).join(UserInfo).all()
for result in results:
    print(f"Name: {result.name}, Address: {result.address}")


# 按照用户名查询单个用户信息
result = db.query(User.name, UserInfo.address).join(UserInfo).filter(User.name == '').first()
print(result, type(result))  # 类型:<class 'sqlalchemy.engine.row.Row'>

 使用 subquery 进行跨表查询

from sqlalchemy.orm import aliased
from sqlalchemy.sql import select

# 创建别名
userinfo_alias = aliased(UserInfo)

# 创建子查询
subquery = db.query(userinfo_alias.id, userinfo_alias.address).subquery()

# 使用子查询进行查询
results = db.query(User.name, subquery.c.address).join(subquery, User.userinfo_id == subquery.c.id).all()

for result in results:
    print(f"Name: {result.name}, Address: {result.address}")

使用 outerjoin 进行左连接查询

如果你需要进行左连接查询(即即使某些用户没有对应的 UserInfo 也能查询到),可以使用 outerjoin

# 查询所有用户的姓名和地址,即使某些用户没有对应的 UserInfo
results = db.query(User.name, UserInfo.address).outerjoin(UserInfo).all()

for result in results:
    print(f"Name: {result.name}, Address: {result.address or 'N/A'}")

删除的话肯定要先删除有外键的,然后再删除没有外键的

;