)
第2章创建表与增加记录2.1 定义模型类 定义表结构fromsqlalchemyimportcreate_engine,Column,Integer,String,Floatfromsqlalchemy.ormimportDeclarativeBase,Session# 1. 定义基类classBase(DeclarativeBase):pass# 2. 定义模型类一张表对应一个类classStudent(Base):# 表名必填__tablename__students# 列定义idColumn(Integer,primary_keyTrue,autoincrementTrue)# 主键自增nameColumn(String(50),nullableFalse)# 姓名不能为空ageColumn(Integer,default18)# 年龄默认18scoreColumn(Float)# 成绩可为空# 可选定义打印时的显示内容def__repr__(self):returnfStudent(id{self.id}, name{self.name}, age{self.age})Column 常用参数参数说明示例primary_keyTrue设为主键idautoincrementTrue自动递增idnullableFalse不允许为空必填字段uniqueTrue值唯一不重复邮箱、用户名default值默认值default18indexTrue创建索引加速查询经常被查询的字段常用列类型SQLAlchemy 类型对应 Python 类型说明Integerint整数String(长度)str字符串Floatfloat浮点数Booleanbool布尔值DateTimedatetime日期时间Textstr长文本Enumenum枚举值2.2 创建表# 创建引擎enginecreate_engine(sqlite:///school.db,echoTrue)# 根据所有继承 Base 的模型类在数据库中创建对应的表Base.metadata.create_all(engine)# 注意如果表已存在不会重复创建不会覆盖数据2.3 添加记录增 / Create# 方式一逐条添加withSession(engine)assession:s1Student(name张三,age20,score88.5)session.add(s1)# 加入 sessionsession.commit()# 提交到数据库必须# 方式二批量添加withSession(engine)assession:students[Student(name李四,age21,score92.0),Student(name王五,age19,score76.5),Student(name赵六,age22,score85.0),Student(name钱七,age20,score90.0),Student(name孙八,age18,score79.0),Student(name周九,age19,score82.5),Student(name吴十,age20),Student(name郑一,age21,score87.0),Student(name王二,age22,score91.5),Student(name冯三,age23,score75.0),Student(name陈四,age24),Student(name褚五,age25,score88.0),Student(name卫六,age18,score80.5),Student(name蒋七,age19,score93.0),Student(name沈八,age20,score77.5),Student(name韩九,age21),Student(name杨十,age22,score84.0),Student(name朱一,age23,score90.5),Student(name秦二,age24,score72.0),Student(name尤三,age25),Student(name许四,age18,score86.5),Student(name何五,age19,score78.0),Student(name吕六,age20,score92.5),Student(name施七,age21),Student(name张八,age22,score81.0),Student(name孔九,age23,score76.0),Student(name曹十,age24),Student(name严一,age25,score89.5),]session.add_all(students)# 一次性添加多条session.commit()# 方式三add 后立即刷新获取 IDwithSession(engine)assession:sStudent(name华二,age18,scoreNone)session.add(s)session.flush()# 将 SQL 发送到数据库但不提交事务print(s,s.id,s.name)# 此时可以获取到自动生成的 idsession.commit()# 确认提交add vs flush vs commit 的区别add(obj) → 把对象标记为待插入pending 状态 flush() → 把 SQL 发到数据库执行但不提交事务。此时可以获取自增ID commit() → 提交事务数据永久写入数据库2.4 完整示例fromsqlalchemyimportcreate_engine,Column,Integer,String,Floatfromsqlalchemy.ormimportDeclarativeBase,SessionclassBase(DeclarativeBase):passclassStudent(Base):__tablename__studentsidColumn(Integer,primary_keyTrue,autoincrementTrue)nameColumn(String(50),nullableFalse)ageColumn(Integer,default18)scoreColumn(Float)def__repr__(self):returnfStudent(id{self.id}, name{self.name})# 创建引擎和表enginecreate_engine(sqlite:///school.db,echoFalse)Base.metadata.create_all(engine)# 添加学生withSession(engine)assession:session.add_all([Student(name张三,age20,score88.5),Student(name李四,age21,score92.0),Student(name王五,age19,score76.5),Student(name赵六,age22,score85.0),])session.commit()print(学生数据添加成功)第3章查询记录3.1 查询所有记录withSession(engine)assession:# 查询全部all_studentssession.query(Student).all()forsinall_students:print(s)# 查询总数countsession.query(Student).count()print(f共有{count}名学生)3.2 条件查询withSession(engine)assession:# 精确匹配zhangsession.query(Student).filter(Student.name张三).first()# 多条件ANDresultsession.query(Student).filter(Student.age20,Student.score80).all()# 多条件ORfromsqlalchemyimportor_ resultsession.query(Student).filter(or_(Student.name张三,Student.name李四)).all()# 模糊查询resultsession.query(Student).filter(Student.name.like(%三%)# % 是通配符匹配任意字符).all()# IN 查询resultsession.query(Student).filter(Student.name.in_([张三,李四,王五])).all()# 范围查询resultsession.query(Student).filter(Student.score.between(80,100)).all()# 判空 / 非空resultsession.query(Student).filter(Student.score.is_(None)).all()resultsession.query(Student).filter(Student.score.isnot(None)).all()3.3 排序withSession(engine)assession:# 升序studentssession.query(Student).order_by(Student.score).all()# 降序studentssession.query(Student).order_by(Student.score.desc()).all()# 多级排序先按年龄升序同年龄按成绩降序studentssession.query(Student).order_by(Student.age,Student.score.desc()).all()3.4 分页LIMIT / OFFSETwithSession(engine)assession:# 取前5条top5session.query(Student).limit(5).all()# 跳过前10条取5条第三页page2session.query(Student).offset(10).limit(5).all()# 分页公式第 N 页 offset((N-1) * page_size).limit(page_size)page2page_size10resultsession.query(Student)\.offset((page-1)*page_size)\.limit(page_size)\.all()3.5 聚合查询fromsqlalchemyimportfuncwithSession(engine)assession:# 最大值、最小值、平均值、总和max_scoresession.query(func.max(Student.score)).scalar()min_scoresession.query(func.min(Student.score)).scalar()avg_scoresession.query(func.avg(Student.score)).scalar()sum_scoresession.query(func.sum(Student.score)).scalar()# 分组统计每个年龄有多少人resultsession.query(Student.age,func.count(Student.id)).group_by(Student.age).all()# 分组后过滤HAVING人数大于2的年龄resultsession.query(Student.age,func.count(Student.id)).group_by(Student.age).having(func.count(Student.id)2).all()3.6 返回指定列投影查询withSession(engine)assession:# 只查询姓名和成绩resultsession.query(Student.name,Student.score).all()forname,scoreinresult:print(f{name}:{score})# 查询去重agessession.query(Student.age).distinct().all()3.7 first() / one() / scalar() 的区别# .first() — 返回第一条记录没有则返回 None最常用studentsession.query(Student).filter(Student.name张三).first()# .one() — 必须恰好一条多了或少了都报错严格校验时使用studentsession.query(Student).filter(Student.id1).one()# .one_or_none() — 零或一条多条则报错studentsession.query(Student).filter(Student.name陈四).one_or_none()# .scalar() — 返回第一条的第一个字段值countsession.query(func.count(Student.id)).scalar()# .all() — 返回所有记录组成的列表studentssession.query(Student).all()第4章更新与删除4.1 更新记录改 / UpdatewithSession(engine)assession:# 方式1先查后改推荐有对象可以进一步操作studentsession.query(Student).filter(Student.name张三).first()ifstudent:student.age21student.score95.0session.commit()# 方式2批量更新不需先查出对象session.query(Student).filter(Student.age20).update({age:20},synchronize_sessionfetch)session.commit()4.2 删除记录删 / DeletewithSession(engine)assession:# 方式1先查后删studentsession.query(Student).filter(Student.name王五).first()ifstudent:session.delete(student)session.commit()# 方式2批量删除session.query(Student).filter(Student.scoreNone).delete(synchronize_sessionfetch)session.commit()4.3 CRUD 完整练习fromsqlalchemyimportcreate_engine,Column,Integer,String,Floatfromsqlalchemy.ormimportDeclarativeBase,SessionclassBase(DeclarativeBase):passclassProduct(Base):__tablename__productsidColumn(Integer,primary_keyTrue,autoincrementTrue)nameColumn(String(100),nullableFalse)priceColumn(Float,nullableFalse)stockColumn(Integer,default0)def__repr__(self):returnfProduct(id{self.id}, name{self.name}, price{self.price}, stock{self.stock})enginecreate_engine(sqlite:///shop.db,echoFalse)Base.metadata.create_all(engine)# 增添加商品withSession(engine)assession:session.add_all([Product(name笔记本电脑,price5999.0,stock50),Product(name无线鼠标,price99.0,stock200),Product(name机械键盘,price399.0,stock80),Product(name显示器,price1999.0,stock30),Product(nameRTX 5090 32GBGDDR7,price28888.0,stock0)])session.commit()# 查查看所有商品withSession(engine)assession:productssession.query(Product).all()forpinproducts:print(f{p.name}- 价格: ¥{p.price}, 库存:{p.stock})# 改鼠标涨价withSession(engine)assession:mousesession.query(Product).filter(Product.name无线鼠标).first()mouse.price129.0session.commit()# 删删除库存为0的商品withSession(engine)assession:session.query(Product).filter(Product.stock0).delete()session.commit()# 查统计withSession(engine)assession:countsession.query(Product).count()print(f当前共有{count}种商品)