Python-ORM
1、ORM
ORM:对象关系映射,对象和关系之间的映射,使用面向对象的方式来操作数据库
关系模型和 Python对象之间的映射
table ===> class , 表映射为类
row ===> object , 行映射为实例
column ===> property, 字段映射为属性
举例:
有表student, 字段为 id int, name varchar, age int
映射到python中:
1 class Student: 2 id = ?某类型字段 3 name = ?某类型字段 4 age = ?某类型字段 5 最终得到实例: 6 7 class Student: 8 def __init__(self): 9 self.id =? 10 self.name = ? 11 self.age = ?
2、SQLAlchemy:
SQLAlchemy 是一个ORM框架
安装: $ pip install sqlachemy
文档:https://docs.sqlalchemy.org/en/latest/
查看版本:
import sqlalchemy print(sqlalchemy.__version__)
开发:SQLAlchemy 内部使用了 连接池
3、创建连接池
数据库连接的事情,交给引擎
dialect + driver:// username:password@host:port/ database
方言(dialect):支持mysql, oracle等
驱动(dirver):封装好的驱动,此处 pymysql, mysqldb只支持 python2
mysqldb的链接
1 mysql + mysqldb://<user>:<password>@<host>[:<posrt>]/<dbname> 2 enging = sqlalchemy,create_engine('mysql +mysqldb://root:123456@127.0.0.1:3306/test')
pymysql的链接(echo=True 表示开启debug功能,打印一些调试信息)
enging = create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/testt',echo=True)
注意:创建引擎并不会马上连接数据库,直到让数据库执行任务时才连接
4、Declare a Mapping 创建映射
1 from sqlalchemy import create_engine,Column, Integer, String 2 from sqlalchemy.ext.declarative import declarative_base 3 4 enging = create_engine('mysql+pymysql://root:123456@192.168.112.111:3306/testt', echo=True) 5 6 7 # 创建 基类,所有的实体类必须继承此基类 8 Base = declarative_base() 9 10 # 创建实体类 11 class Student(Base): 12 # 指定表名(必须指定) 13 __tablename__ = 'student' 14 # 定义类属性 ====> 对应字段,如果 属性 标识符(如 age) 跟字段名一致,则,Column中不需要指定,否则,根据需要指定 15 id = Column(Integer, primary_key=True, autoincrement=True) 16 name = Column(String(12), nullable=True) 17 age = Column(Integer) 18 19 def __repr__(self): 20 return '{} id={} name={} age={}'.format(self.__class__.name, self.id,self.name, self.age) 21 22 # 查看表结构 23 print(Student) 24 print(repr(Student.__table__)) 25 ''' 26 <class '__main__.Student'> 27 Table('student', MetaData(bind=None), Column('id', Integer(), table=<student>, primary_key=True, nullable=False), Column('name', String(length=12), table=<student>), Column('age', Integer(), table=<student>), schema=None) 28 '''
22 # 实例化 ===> 新建一行,对应 row 23 s = Student(name='tom') 24 s.age = 20 # 这里使用了描述性,因为Column是类,并实例化为一个实体类的属性 25 # print(s.age, s.name) 26 27 # 创建表 28 # 可以使用SQLAlchemy 来创建表,删除表 29 # 删除继承自Base的所有表,所有的表,都是 归 Base 基类管理的 30 Base.metadata.drop_all(enging) 31 # 创建继承自Base的所有的表 32 Base.metadata.create_all(enging) 33 34 ''' 35 执行结果: 部分 echo=True 的信息:可以看到执行后的SQL 语句是否是自己想要的。 36 CREATE TABLE student ( 37 id INTEGER NOT NULL AUTO_INCREMENT, 38 name VARCHAR(12), 39 age INTEGER, 40 PRIMARY KEY (id) 41 ) 42 43 44 2018-11-12 10:24:38,679 INFO sqlalchemy.engine.base.Engine {} 45 2018-11-12 10:24:38,740 INFO sqlalchemy.engine.base.Engine COMMIT 46 '''
注意:
生产环境总很少这样创建表,都是系统上线的时候由脚本生成。
生成环境很少删除表,宁可废弃,都不删除。
如果数据库中有 表,只是对此表操作,实体类,字段的属性 的 定义事实上是可以省略的,为了方便阅读,还是写上基本的,如唯一键等,可以不写。
1 # 创建会话 session 2 # 在一个会话中操作数据库,会话建立在连接 上,连接被 引擎管理。 3 # 当第一次使用数据库时,从引擎维护的链接池中获取一个连接使用 4 Session = sessionmaker(bind=engine) # 返回一个 Session 类 5 session = Session() # 实例化一个session 6 # 依然在第一次使用时连接数据库 7 session 对象线程不安全,所以不同线程应该使用不同的session对象 8 Session 类和engine 有一个就行了
5、CRUD操作
增:
1 # 增 2 ''' 3 add() 增加一个对象 4 add_all() 可迭代对象,元素是对象 5 ''' 6 7 session.add(s) 8 session.commit() 9 10 # 最好使用 try ,出现问题,一般都要回滚 11 try: 12 session.add_all([s]) # 如果多个实例,则使用 add_all 13 session.commit() # 提交 不成功。 14 print('=====================================') 15 except Exception as e: 16 session.rollback() 17 raise 18 # add_all() 方法 不会提交成功,是s 第一次提交之后,s的主键有了值, 19 # 所以,只要 s 没有修改过,就认为没有改动, 20 try: 21 s.name = 'lucy' # 这里 是 对之前的s 做了update操作,所以再次提交,就可以提交成功 22 session.add_all([s]) # 如果多个实例,则使用 add_all 23 session.commit() # 提交 不成功。 24 except Exception as e: 25 session.rollback() 26 raise
s 主键没有值,就是新增; 主键有值, 就是找到主键对应的记录修改,因为第一次提交后,通过打印发现 s.id 是有值的
简单查询:
1 # 使用 query() 方法,返回一个Query 对象 2 students= session.query(Student) # SELECT * FROM student 3 print('===', students) # 打印 发现只是一个SQL语句,并不是查询到的结果 4 for student in students: 5 print(student) 6 7 # SELECT * FROM student where id = 2 8 student = session.query(Student).get(2) # 通过主键查询 9 print('---', student)
query 方法将 实体类传入,返回类的对象可迭代对象,这时候不必查询,迭代它 就执行SQL来查询数据库
封装数据到指定类的实例
get 方法使用主键查询,返回一条传入类的一个实例。
改:
1 student = session.query(Student).get(2) 2 print('========', student) 3 student.name = 'sam1' 4 student.age = 30 5 print('========',student) 6 session.add(student) 7 session.commit()
先查回来,在修改,再提交修改。
删:
1 # 删除 2 try: 3 student = Student(id=2, name='sam1',age=30) 4 session.delete(student) 5 session.commit() 6 except Exception as e: 7 session.rollback() 8 print(e)
但是,这是Student实体类 实例化出的新的一个实例,虽然表中可能有此row,但是此时,删除的是这个新实例
,而这个实例并没有 持久化(commit),所以报错:
Instance '<Student at 0x38bfd30>' is not persisted
状态***
每一个实体,都有一个状态属性 _sa_instance_state,其类型是sqlalchemy.orm.state.instanceState
可以使用 sqlalchemy.inspect(entity) 函数查看状态。
常见的状态值 transient(临时的),pending(预备好的),persistent(持久的),deleted(删除的),detached(分裂的)。
新建一个实体,状态是 transient 临时的
一旦add() 后,从transient 变成 pending状态
成功commit 后,变成persistent
成功查询返回的实体对象,也是persistent状态
persistent 状态的实体,修改依然是persisitent状态
persistent状态的实体,删除后,flush后但没有commit,就变成deleted状态,成功提交,变成detached状态
提交失败,还原到persistent状态,flush方法,主动把改变应用到数据库中。
删除,修改操作,需要对应一个真实的记录,所以要求实体对象是persistent状态
测试1:
1 from sqlalchemy import create_engine,Column, Integer, String 2 from sqlalchemy.orm import sessionmaker 3 from sqlalchemy.ext.declarative import declarative_base 4 import sqlalchemy 5 6 engine = create_engine('mysql+pymysql://root:123456@192.168.112.111:3306/test', echo=True) 7 8 # 创建 基类,所有的实体类必须继承此基类 9 Base = declarative_base() 10 11 # 创建实体类 12 class Student(Base): 13 # 指定表名(必须指定) 14 __tablename__ = 'student' 15 # 定义类属性 ====> 对应字段 16 id = Column(Integer, primary_key=True, autoincrement=True) 17 name = Column(String(12), nullable=True) 18 age = Column(Integer) 19 20 def __repr__(self): 21 return '{} id={} name={} age={}'.format(self.__class__.__name__, self.id,self.name, self.age) 22 23 Session = sessionmaker(bind=engine) 24 session = Session() 25 26 from sqlalchemy.orm.state import InstanceState 27 def getstate(entity,i): 28 insp = sqlalchemy.inspect(entity) 29 state = 'session={}, attache={}\n' \ 30 'transient={}, persistent={}\n' \ 31 'pending={}, deleted={}, detached={}'.format( 32 insp.session_id, 33 insp._attached, 34 insp.transient, 35 insp.persistent, 36 insp.pending, 37 insp.deleted, 38 insp.detached) 39 print(i, state) 40 print(insp.key) 41 42 student = session.query(Student).get(2) 43 getstate(student, 1) 44 45 try: 46 student = Student(id=2,name='sam', age=30) 47 getstate(student, 2) 48 49 student = Student(name='sammy', age=30) 50 getstate(student, 3) 51 52 session.add(student) 53 getstate(student, 4) 54 55 session.commit() 56 getstate(student, 5) 57 58 except Exception as e: 59 session.rollback() 60 print(e)
结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 1 session=1, attache=True 2 transient=False, persistent=True 3 pending=False, deleted=False, detached=False 4 (<class '__main__.Student'>, (2,), None) 5 2 session=None, attache=False 6 transient=True, persistent=False 7 pending=False, deleted=False, detached=False 8 None 9 3 session=None, attache=False 10 transient=True, persistent=False 11 pending=False, deleted=False, detached=False 12 None 13 4 session=1, attache=True 14 transient=False, persistent=False 15 pending=True, deleted=False, detached=False 16 None 17 5 session=1, attache=True 18 transient=False, persistent=True 19 pending=False, deleted=False, detached=False 20 (<class '__main__.Student'>, (6,), None)
测试 2:
1 student = session.query(Student).get(3) 2 print(student) 3 getstate(student, 1) 4 5 try: 6 # 删除的前提是 persistent 7 session.delete(student) 8 getstate(student, 2) # 没有flush,还是persistent 9 session.flush() 10 getstate(student, 3) 11 session.commit() 12 getstate(student, 4) 13 except Exception as e: 14 session.rollback() 15 print(e)
结果2:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt17.py 2 Student id=3 name=tom age=20 3 1 session=1, attache=True 4 transient=False, persistent=True 5 pending=False, deleted=False, detached=False 6 (<class '__main__.Student'>, (3,), None) 7 2 session=1, attache=True 8 transient=False, persistent=True 9 pending=False, deleted=False, detached=False 10 (<class '__main__.Student'>, (3,), None) 11 3 session=1, attache=True 12 transient=False, persistent=False 13 pending=False, deleted=True, detached=False 14 (<class '__main__.Student'>, (3,), None) 15 4 session=None, attache=False 16 transient=False, persistent=False 17 pending=False, deleted=False, detached=True 18 (<class '__main__.Student'>, (3,), None) 19 20 Process finished with exit code 0
复杂查询:
1 from sqlalchemy import create_engine,Column, Integer, String, Date 2 from sqlalchemy import Enum, ForeignKey, create_engine 3 from sqlalchemy.orm import sessionmaker 4 from sqlalchemy.ext.declarative import declarative_base 5 import sqlalchemy 6 7 import enum # 这里使用的是python 提供的 枚举,sqlalchemy 提供的enum 不能使用 8 9 class MyEnum(enum.Enum): 10 M = 'M' 11 F = 'F' 12 13 14 engine = create_engine('mysql+pymysql://root:123456@192.168.112.111:3306/test', echo =True) 15 Session = sessionmaker(bind=engine) 16 session = Session() 17 18 Base = declarative_base() 19 20 class Employee(Base): 21 __tablename__ = 'employees' 22 emp_no = Column(Integer, primary_key=True) 23 birth_date = Column() 24 first_name = Column() 25 last_name = Column() 26 gender = Column(Enum(MyEnum)) 27 hire_date = Column(Date) 28 29 def __repr__(self): 30 return "{} no={} name='{} {}' !!!gender={} gender={}".format( 31 self.__class__.__name__,self.emp_no, self.first_name,self.last_name, 32 self.gender, 33 self.gender.value 34 ) 35 36 # 打印函数 37 def show(emps): 38 for x in emps: 39 print(x) 40 print('======'*15, end='\n\n') 41 42 # 简单条件查询 43 emps = session.query(Employee).filter(Employee.emp_no > 10015) 44 show(emps) 45 46 # 与或非 47 from sqlalchemy import or_, and_, not_, 其他的是自带的,不需要导入 48 # AND 条件 49 # 方式 1: 多级filter 表示 AND,注意一点,这是Python代码,所以不能以SQL 语句的条件判断符 表示,例如 =,<=>, <> 50 emps = session.query(Employee).filter(Employee.emp_no > 10015).filter(Employee.gender ==MyEnum.F) 51 show(emps) 52 # 方式 2:使用 模块提供 and_ 53 emps = session.query(Employee).filter(and_(Employee.emp_no > 10015, Employee.gender == MyEnum.F)) 54 show(emps) 55 # 方式 3: 使用 & 符号, 但是注意,& 两边的条件,要用括号,负责可能出现问题。 56 emps = session.query(Employee).filter((Employee.emp_no >10015) & (Employee.gender == MyEnum.F)) 57 show(emps) 58 59 # OR 条件 60 # 方式 1: | 符号,注意括号 61 emps = session.query(Employee).filter((Employee.emp_no > 10018) | (Employee.emp_no < 10003)) 62 show(emps) 63 # 方式 2: or_ 64 emps = session.query(Employee).filter(or_(Employee.emp_no > 10018, Employee.emp_no < 10003)) 65 show(emps) 66 67 # NOT 条件 68 # 方式 1:not_ 69 emps = session.query(Employee).filter(not_(Employee.emp_no < 10018)) 70 show(emps) 71 # 方式 2: ~ 72 emps = session.query(Employee).filter(~(Employee.emp_no < 10018)) 73 show(emps) 74 75 # in 操作 76 emplist = [10010, 10012, 10018, 1000000000] 77 emps = session.query(Employee).filter(Employee.emp_no.in_(emplist)) 78 show(emps) 79 80 # not in 操作 81 emps = session.query(Employee).filter(Employee.emp_no.notin_(emplist)) 82 show(emps) 83 84 # like 85 emps = session.query(Employee).filter(Employee.last_name.like('P%')) 86 show(emps) 87 # not like 88 emps = session.query(Employee).filter(Employee.last_name.notlike('P%')) 89 show(emps) 90 91 # ilike :不区分大小写 92 93 # 排序 94 # 升序 95 emps = session.query(Employee).filter(Employee.emp_no > 10010).order_by(Employee.emp_no) 96 emps = session.query(Employee).filter(Employee.emp_no > 10010).order_by(Employee.emp_no.asc()) 97 show(emps) 98 # 降序 99 emps = session.query(Employee).filter(Employee.emp_no > 10010).order_by(Employee.emp_no.desc()) 100 show(emps) 101 102 # 多列排序 :select * from Employee where emp_no > 10010 order by first_name, last_name desc 103 emps = session.query(Employee).filter(Employee.emp_no > 10010 104 ).order_by(Employee.last_name).order_by(Employee.last_name.desc()) 105 show(emps) 106 107 # 分页 108 emps = session.query(Employee).limit(4) 109 show(emps) 110 emps = session.query(Employee).limit(4).offset(3) # 位移 3 个,显示 4 个 111 show(emps)
结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt17.py 2 2018-11-12 16:00:20,499 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode' 3 2018-11-12 16:00:20,500 INFO sqlalchemy.engine.base.Engine {} 4 2018-11-12 16:00:20,501 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'lower_case_table_names' 5 2018-11-12 16:00:20,501 INFO sqlalchemy.engine.base.Engine {} 6 2018-11-12 16:00:20,503 INFO sqlalchemy.engine.base.Engine SELECT DATABASE() 7 2018-11-12 16:00:20,503 INFO sqlalchemy.engine.base.Engine {} 8 2018-11-12 16:00:20,506 INFO sqlalchemy.engine.base.Engine show collation where `Charset` = 'utf8mb4' and `Collation` = 'utf8mb4_bin' 9 2018-11-12 16:00:20,506 INFO sqlalchemy.engine.base.Engine {} 10 2018-11-12 16:00:20,508 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAR(60)) AS anon_1 11 2018-11-12 16:00:20,508 INFO sqlalchemy.engine.base.Engine {} 12 2018-11-12 16:00:20,509 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_1 13 2018-11-12 16:00:20,509 INFO sqlalchemy.engine.base.Engine {} 14 2018-11-12 16:00:20,510 INFO sqlalchemy.engine.base.Engine SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin AS anon_1 15 2018-11-12 16:00:20,510 INFO sqlalchemy.engine.base.Engine {} 16 2018-11-12 16:00:20,512 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 17 2018-11-12 16:00:20,513 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 18 FROM employees 19 WHERE employees.emp_no > %(emp_no_1)s 20 2018-11-12 16:00:20,513 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10015} 21 Employee no=10016 name='Kazuhito Cappelletti' !!!gender=MyEnum.M gender=M 22 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 23 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 24 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 25 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 26 ========================================================================================== 27 28 2018-11-12 16:00:20,516 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 29 FROM employees 30 WHERE employees.emp_no > %(emp_no_1)s AND employees.gender = %(gender_1)s 31 2018-11-12 16:00:20,516 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10015, 'gender_1': 'F'} 32 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 33 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 34 ========================================================================================== 35 36 2018-11-12 16:00:20,519 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 37 FROM employees 38 WHERE employees.emp_no > %(emp_no_1)s AND employees.gender = %(gender_1)s 39 2018-11-12 16:00:20,519 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10015, 'gender_1': 'F'} 40 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 41 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 42 ========================================================================================== 43 44 2018-11-12 16:00:20,521 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 45 FROM employees 46 WHERE employees.emp_no > %(emp_no_1)s AND employees.gender = %(gender_1)s 47 2018-11-12 16:00:20,521 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10015, 'gender_1': 'F'} 48 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 49 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 50 ========================================================================================== 51 52 2018-11-12 16:00:20,523 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 53 FROM employees 54 WHERE employees.emp_no > %(emp_no_1)s OR employees.emp_no < %(emp_no_2)s 55 2018-11-12 16:00:20,523 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10018, 'emp_no_2': 10003} 56 Employee no=10001 name='Georgi Facello' !!!gender=MyEnum.M gender=M 57 Employee no=10002 name='Bezalel Simmel' !!!gender=MyEnum.F gender=F 58 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 59 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 60 ========================================================================================== 61 62 2018-11-12 16:00:20,526 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 63 FROM employees 64 WHERE employees.emp_no > %(emp_no_1)s OR employees.emp_no < %(emp_no_2)s 65 2018-11-12 16:00:20,526 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10018, 'emp_no_2': 10003} 66 Employee no=10001 name='Georgi Facello' !!!gender=MyEnum.M gender=M 67 Employee no=10002 name='Bezalel Simmel' !!!gender=MyEnum.F gender=F 68 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 69 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 70 ========================================================================================== 71 72 2018-11-12 16:00:20,527 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 73 FROM employees 74 WHERE employees.emp_no >= %(emp_no_1)s 75 2018-11-12 16:00:20,528 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10018} 76 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 77 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 78 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 79 ========================================================================================== 80 81 2018-11-12 16:00:20,530 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 82 FROM employees 83 WHERE employees.emp_no >= %(emp_no_1)s 84 2018-11-12 16:00:20,530 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10018} 85 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 86 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 87 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 88 ========================================================================================== 89 90 2018-11-12 16:00:20,532 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 91 FROM employees 92 WHERE employees.emp_no IN (%(emp_no_1)s, %(emp_no_2)s, %(emp_no_3)s, %(emp_no_4)s) 93 2018-11-12 16:00:20,533 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010, 'emp_no_2': 10012, 'emp_no_3': 10018, 'emp_no_4': 1000000000} 94 Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F 95 Employee no=10012 name='Patricio Bridgland' !!!gender=MyEnum.M gender=M 96 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 97 ========================================================================================== 98 99 2018-11-12 16:00:20,535 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 100 FROM employees 101 WHERE employees.emp_no NOT IN (%(emp_no_1)s, %(emp_no_2)s, %(emp_no_3)s, %(emp_no_4)s) 102 2018-11-12 16:00:20,535 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010, 'emp_no_2': 10012, 'emp_no_3': 10018, 'emp_no_4': 1000000000} 103 Employee no=10001 name='Georgi Facello' !!!gender=MyEnum.M gender=M 104 Employee no=10002 name='Bezalel Simmel' !!!gender=MyEnum.F gender=F 105 Employee no=10003 name='Parto Bamford' !!!gender=MyEnum.M gender=M 106 Employee no=10004 name='Chirstian Koblick' !!!gender=MyEnum.M gender=M 107 Employee no=10005 name='Kyoichi Maliniak' !!!gender=MyEnum.M gender=M 108 Employee no=10006 name='Anneke Preusig' !!!gender=MyEnum.F gender=F 109 Employee no=10007 name='Tzvetan Zielinski' !!!gender=MyEnum.F gender=F 110 Employee no=10008 name='Saniya Kalloufi' !!!gender=MyEnum.M gender=M 111 Employee no=10009 name='Sumant Peac' !!!gender=MyEnum.F gender=F 112 Employee no=10011 name='Mary Sluis' !!!gender=MyEnum.F gender=F 113 Employee no=10013 name='Eberhardt Terkki' !!!gender=MyEnum.M gender=M 114 Employee no=10014 name='Berni Genin' !!!gender=MyEnum.M gender=M 115 Employee no=10015 name='Guoxiang Nooteboom' !!!gender=MyEnum.M gender=M 116 Employee no=10016 name='Kazuhito Cappelletti' !!!gender=MyEnum.M gender=M 117 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 118 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 119 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 120 ========================================================================================== 121 122 2018-11-12 16:00:20,538 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 123 FROM employees 124 WHERE employees.last_name LIKE %(last_name_1)s 125 2018-11-12 16:00:20,538 INFO sqlalchemy.engine.base.Engine {'last_name_1': 'P%'} 126 Employee no=10006 name='Anneke Preusig' !!!gender=MyEnum.F gender=F 127 Employee no=10009 name='Sumant Peac' !!!gender=MyEnum.F gender=F 128 Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F 129 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 130 ========================================================================================== 131 132 2018-11-12 16:00:20,540 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 133 FROM employees 134 WHERE employees.last_name NOT LIKE %(last_name_1)s 135 2018-11-12 16:00:20,540 INFO sqlalchemy.engine.base.Engine {'last_name_1': 'P%'} 136 Employee no=10001 name='Georgi Facello' !!!gender=MyEnum.M gender=M 137 Employee no=10002 name='Bezalel Simmel' !!!gender=MyEnum.F gender=F 138 Employee no=10003 name='Parto Bamford' !!!gender=MyEnum.M gender=M 139 Employee no=10004 name='Chirstian Koblick' !!!gender=MyEnum.M gender=M 140 Employee no=10005 name='Kyoichi Maliniak' !!!gender=MyEnum.M gender=M 141 Employee no=10007 name='Tzvetan Zielinski' !!!gender=MyEnum.F gender=F 142 Employee no=10008 name='Saniya Kalloufi' !!!gender=MyEnum.M gender=M 143 Employee no=10011 name='Mary Sluis' !!!gender=MyEnum.F gender=F 144 Employee no=10012 name='Patricio Bridgland' !!!gender=MyEnum.M gender=M 145 Employee no=10013 name='Eberhardt Terkki' !!!gender=MyEnum.M gender=M 146 Employee no=10014 name='Berni Genin' !!!gender=MyEnum.M gender=M 147 Employee no=10015 name='Guoxiang Nooteboom' !!!gender=MyEnum.M gender=M 148 Employee no=10016 name='Kazuhito Cappelletti' !!!gender=MyEnum.M gender=M 149 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 150 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 151 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 152 ========================================================================================== 153 154 2018-11-12 16:00:20,543 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 155 FROM employees 156 WHERE employees.emp_no > %(emp_no_1)s ORDER BY employees.emp_no ASC 157 2018-11-12 16:00:20,543 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 158 Employee no=10011 name='Mary Sluis' !!!gender=MyEnum.F gender=F 159 Employee no=10012 name='Patricio Bridgland' !!!gender=MyEnum.M gender=M 160 Employee no=10013 name='Eberhardt Terkki' !!!gender=MyEnum.M gender=M 161 Employee no=10014 name='Berni Genin' !!!gender=MyEnum.M gender=M 162 Employee no=10015 name='Guoxiang Nooteboom' !!!gender=MyEnum.M gender=M 163 Employee no=10016 name='Kazuhito Cappelletti' !!!gender=MyEnum.M gender=M 164 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 165 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 166 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 167 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 168 ========================================================================================== 169 170 2018-11-12 16:00:20,546 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 171 FROM employees 172 WHERE employees.emp_no > %(emp_no_1)s ORDER BY employees.emp_no DESC 173 2018-11-12 16:00:20,546 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 174 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 175 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 176 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 177 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 178 Employee no=10016 name='Kazuhito Cappelletti' !!!gender=MyEnum.M gender=M 179 Employee no=10015 name='Guoxiang Nooteboom' !!!gender=MyEnum.M gender=M 180 Employee no=10014 name='Berni Genin' !!!gender=MyEnum.M gender=M 181 Employee no=10013 name='Eberhardt Terkki' !!!gender=MyEnum.M gender=M 182 Employee no=10012 name='Patricio Bridgland' !!!gender=MyEnum.M gender=M 183 Employee no=10011 name='Mary Sluis' !!!gender=MyEnum.F gender=F 184 ========================================================================================== 185 186 2018-11-12 16:00:20,548 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 187 FROM employees 188 WHERE employees.emp_no > %(emp_no_1)s ORDER BY employees.last_name, employees.last_name DESC 189 2018-11-12 16:00:20,549 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 190 Employee no=10017 name='Cristinel Bouloucos' !!!gender=MyEnum.F gender=F 191 Employee no=10012 name='Patricio Bridgland' !!!gender=MyEnum.M gender=M 192 Employee no=10016 name='Kazuhito Cappelletti' !!!gender=MyEnum.M gender=M 193 Employee no=10014 name='Berni Genin' !!!gender=MyEnum.M gender=M 194 Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M 195 Employee no=10015 name='Guoxiang Nooteboom' !!!gender=MyEnum.M gender=M 196 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 197 Employee no=10011 name='Mary Sluis' !!!gender=MyEnum.F gender=F 198 Employee no=10013 name='Eberhardt Terkki' !!!gender=MyEnum.M gender=M 199 Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M 200 ========================================================================================== 201 202 2018-11-12 16:00:20,551 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 203 FROM employees 204 LIMIT %(param_1)s 205 2018-11-12 16:00:20,551 INFO sqlalchemy.engine.base.Engine {'param_1': 4} 206 Employee no=10001 name='Georgi Facello' !!!gender=MyEnum.M gender=M 207 Employee no=10002 name='Bezalel Simmel' !!!gender=MyEnum.F gender=F 208 Employee no=10003 name='Parto Bamford' !!!gender=MyEnum.M gender=M 209 Employee no=10004 name='Chirstian Koblick' !!!gender=MyEnum.M gender=M 210 ========================================================================================== 211 212 2018-11-12 16:00:20,553 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 213 FROM employees 214 LIMIT %(param_1)s, %(param_2)s 215 2018-11-12 16:00:20,553 INFO sqlalchemy.engine.base.Engine {'param_1': 3, 'param_2': 4} 216 Employee no=10004 name='Chirstian Koblick' !!!gender=MyEnum.M gender=M 217 Employee no=10005 name='Kyoichi Maliniak' !!!gender=MyEnum.M gender=M 218 Employee no=10006 name='Anneke Preusig' !!!gender=MyEnum.F gender=F 219 Employee no=10007 name='Tzvetan Zielinski' !!!gender=MyEnum.F gender=F 220 ========================================================================================== 221 222 223 Process finished with exit code 0
1 # 消费者方法: 2 # 消费者方法调用后,Query 对象(可迭代) 就转换成了一个容器 3 4 # 总行数 5 emps = session.query(Employee).filter(Employee.emp_no >10017) 6 7 print(len(list(emps))) # 返回大量的结果,用list查看,求len 8 print(emps.count())# 聚合函数count(*) 的查询 9 10 # 去所有数据: 11 print(emps.all()) # 返回列表,查不到返回空列表 12 13 # 取首行 14 print(emps.first())# 查不到,返回None 15 16 # 有且只能有一行 17 # print(emps.one()) # 查询 结构多行,抛异常 18 print(emps.limit(1).one()) 19 20 # 删除 delete by query 21 s = session.query(Employee).filter(Employee.emp_no > 10018).delete() 22 print(s) # 返回删除的行数 23 ## 删除后,需要提交,才能生效。 session.commit()
结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 3 2 3 3 [Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F, Employee no=10019 name='Lillian Haddadi' !!!gender=MyEnum.M gender=M, Employee no=10020 name='Mayuko Warwick' !!!gender=MyEnum.M gender=M] 4 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 5 Employee no=10018 name='Kazuhide Peha' !!!gender=MyEnum.F gender=F 6 2
1 # 聚合 分组 2 # 聚合函数 3 from sqlalchemy import func 4 query = session.query(func.count(Employee.emp_no)) 5 print(query) 6 print(query.one()) # 只能有一行结果 7 print(query.scalar()) # 取 one() 返回元组的第一个元素 8 9 # max min avg 10 print(session.query(func.max(Employee.emp_no)).scalar()) 11 print(session.query(func.min(Employee.emp_no)).scalar()) 12 print(session.query(func.avg(Employee.emp_no)).scalar()) 13 14 print('======'*15, end='\n\n') 15 # 分组 16 print(session.query(Employee.gender, 17 func.count(Employee.emp_no)).group_by(Employee.gender).all())
结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt17.py 2 SELECT count(employees.emp_no) AS count_1 3 FROM employees 4 2018-11-12 16:18:22,426 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode' 5 2018-11-12 16:18:22,426 INFO sqlalchemy.engine.base.Engine {} 6 2018-11-12 16:18:22,428 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'lower_case_table_names' 7 2018-11-12 16:18:22,428 INFO sqlalchemy.engine.base.Engine {} 8 2018-11-12 16:18:22,430 INFO sqlalchemy.engine.base.Engine SELECT DATABASE() 9 2018-11-12 16:18:22,430 INFO sqlalchemy.engine.base.Engine {} 10 2018-11-12 16:18:22,431 INFO sqlalchemy.engine.base.Engine show collation where `Charset` = 'utf8mb4' and `Collation` = 'utf8mb4_bin' 11 2018-11-12 16:18:22,431 INFO sqlalchemy.engine.base.Engine {} 12 2018-11-12 16:18:22,433 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAR(60)) AS anon_1 13 2018-11-12 16:18:22,433 INFO sqlalchemy.engine.base.Engine {} 14 2018-11-12 16:18:22,434 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_1 15 2018-11-12 16:18:22,434 INFO sqlalchemy.engine.base.Engine {} 16 2018-11-12 16:18:22,435 INFO sqlalchemy.engine.base.Engine SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin AS anon_1 17 2018-11-12 16:18:22,435 INFO sqlalchemy.engine.base.Engine {} 18 2018-11-12 16:18:22,436 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 19 2018-11-12 16:18:22,437 INFO sqlalchemy.engine.base.Engine SELECT count(employees.emp_no) AS count_1 20 FROM employees 21 2018-11-12 16:18:22,437 INFO sqlalchemy.engine.base.Engine {} 22 (20,) 23 2018-11-12 16:18:22,439 INFO sqlalchemy.engine.base.Engine SELECT count(employees.emp_no) AS count_1 24 FROM employees 25 2018-11-12 16:18:22,439 INFO sqlalchemy.engine.base.Engine {} 26 20 27 2018-11-12 16:18:22,440 INFO sqlalchemy.engine.base.Engine SELECT max(employees.emp_no) AS max_1 28 FROM employees 29 2018-11-12 16:18:22,440 INFO sqlalchemy.engine.base.Engine {} 30 10020 31 2018-11-12 16:18:22,441 INFO sqlalchemy.engine.base.Engine SELECT min(employees.emp_no) AS min_1 32 FROM employees 33 2018-11-12 16:18:22,441 INFO sqlalchemy.engine.base.Engine {} 34 10001 35 2018-11-12 16:18:22,443 INFO sqlalchemy.engine.base.Engine SELECT avg(employees.emp_no) AS avg_1 36 FROM employees 37 2018-11-12 16:18:22,443 INFO sqlalchemy.engine.base.Engine {} 38 10010.5000 39 ========================================================================================== 40 41 2018-11-12 16:18:22,445 INFO sqlalchemy.engine.base.Engine SELECT employees.gender AS employees_gender, count(employees.emp_no) AS count_1 42 FROM employees GROUP BY employees.gender 43 2018-11-12 16:18:22,445 INFO sqlalchemy.engine.base.Engine {} 44 [(<MyEnum.M: 'M'>, 12), (<MyEnum.F: 'F'>, 8)] 45 46 Process finished with exit code 0
关联查询:三张表
1 CREATE TABLE `employees` ( 2 `emp_no` int(11) NOT NULL, 3 `birth_date` date NOT NULL, 4 `first_name` varchar(14) NOT NULL, 5 `last_name` varchar(16) NOT NULL, 6 `gender` enum('M','F') NOT NULL, 7 `hire_date` date NOT NULL, 8 PRIMARY KEY (`emp_no`) 9 ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 10 11 12 13 CREATE TABLE `departments` ( 14 `dept_no` char(4) NOT NULL, 15 `dept_name` varchar(40) NOT NULL, 16 PRIMARY KEY (`dept_no`), 17 UNIQUE KEY `dept_name` (`dept_name`) 18 ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 19 20 21 22 CREATE TABLE `dept_emp` ( 23 `emp_no` int(11) NOT NULL, 24 `dept_no` char(4) NOT NULL, 25 `from_date` date NOT NULL, 26 `to_date` date NOT NULL, 27 PRIMARY KEY (`emp_no`,`dept_no`), 28 KEY `dept_no` (`dept_no`), 29 CONSTRAINT `dept_emp_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE, 30 CONSTRAINT `dept_emp_ibfk_2` FOREIGN KEY (`dept_no`) REFERENCES `departments` (`dept_no`) ON DELETE CASCADE 31 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
dept_emp的设计表:
外键:
从语句看出,员工和部门之间的关系是多对多的关系,先把这些表的Model类 和字段属性建立起来。
需求,查询10010员工 所在的部门编号及员工信息
1 from sqlalchemy import create_engine,Column, Integer, String, Date 2 from sqlalchemy import Enum, ForeignKey, create_engine 3 from sqlalchemy.orm import sessionmaker 4 from sqlalchemy.ext.declarative import declarative_base 5 import sqlalchemy 6 7 import enum # 这里使用的是python 提供的 枚举,sqlalchemy 提供的enum 不能使用 8 9 class MyEnum(enum.Enum): 10 M = 'M' 11 F = 'F' 12 13 14 engine = create_engine('mysql+pymysql://root:123456@192.168.112.111:3306/test', echo=True) 15 Session = sessionmaker(bind=engine) 16 session = Session() 17 18 Base = declarative_base() 19 20 class Employee(Base): 21 __tablename__ = 'employees' 22 emp_no = Column(Integer, primary_key=True) 23 birth_date = Column() 24 first_name = Column() 25 last_name = Column() 26 gender = Column(Enum(MyEnum)) 27 hire_date = Column(Date) 28 29 def __repr__(self): 30 return "{} no={} name='{} {}' !!!gender={} gender={}".format( 31 self.__class__.__name__,self.emp_no, self.first_name,self.last_name, 32 self.gender, 33 self.gender.value 34 ) 35 36 class Department(Base): 37 __tablename__ = 'departments' 38 dept_no = Column(primary_key=True) 39 dept_name = Column(unique=True) 40 41 def __repr__(self): 42 return '{} no={} name={}'.format( 43 type(self).__name__,self.dept_no,self.dept_name 44 ) 45 46 class Dept_emp(Base): 47 __tablename__ = 'dept_emp' 48 49 emp_no = Column(Integer, ForeignKey('employees.emp_no',ondelete='CASCADE'),primary_key=True) 50 dept_no = Column(ForeignKey('departments.dept_no',ondelete='CASCADE'),primary_key=True) 51 from_date = Column() 52 to_date = Column() 53 54 def __repr__(self): 55 return '{} empno={} deptno={}'.format( 56 type(self).__name__,self.emp_no,self.dept_no) 57 58 def show(emps): 59 for x in emps: 60 print(x) 61 print('======'*15, end='\n\n') 62 63 ''' 64 需求,查询10010员工 所在的部门编号及员工信息 65 ''' 66 67 # 1、使用隐式内连接 68 # 查询10010员工的所在部门编号及员工信息 69 results = session.query(Employee, Dept_emp).filter(Employee.emp_no == Dept_emp.emp_no).filter(Employee.emp_no == 10010).all() 70 print(results) 71 show(results) 72 73 # 2、使用 join 74 # 写法 1: 默认是 inner join 75 results = session.query(Employee).join(Dept_emp).filter(Employee.emp_no ==10010).all() 76 print(results) 77 show(results) 78 ''' 79 可以看到默认会添加 ON 条件,但是可能会不准确,这里利用主键,所以是所需结果 80 FROM employees INNER JOIN dept_emp ON employees.emp_no = dept_emp.emp_no 81 WHERE employees.emp_no = %(emp_no_1)s 82 ''' 83 # 写法 2:手动提供条件 84 results = session.query(Employee).join(Dept_emp, Employee.emp_no == Dept_emp.emp_no).filter(Employee.emp_no ==10010).all() 85 print(results) 86 show(results)
结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt17.py 2 2018-11-12 17:25:26,515 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode' 3 2018-11-12 17:25:26,515 INFO sqlalchemy.engine.base.Engine {} 4 2018-11-12 17:25:26,517 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'lower_case_table_names' 5 2018-11-12 17:25:26,517 INFO sqlalchemy.engine.base.Engine {} 6 2018-11-12 17:25:26,519 INFO sqlalchemy.engine.base.Engine SELECT DATABASE() 7 2018-11-12 17:25:26,519 INFO sqlalchemy.engine.base.Engine {} 8 2018-11-12 17:25:26,522 INFO sqlalchemy.engine.base.Engine show collation where `Charset` = 'utf8mb4' and `Collation` = 'utf8mb4_bin' 9 2018-11-12 17:25:26,522 INFO sqlalchemy.engine.base.Engine {} 10 2018-11-12 17:25:26,524 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAR(60)) AS anon_1 11 2018-11-12 17:25:26,524 INFO sqlalchemy.engine.base.Engine {} 12 2018-11-12 17:25:26,525 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_1 13 2018-11-12 17:25:26,525 INFO sqlalchemy.engine.base.Engine {} 14 2018-11-12 17:25:26,526 INFO sqlalchemy.engine.base.Engine SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin AS anon_1 15 2018-11-12 17:25:26,526 INFO sqlalchemy.engine.base.Engine {} 16 2018-11-12 17:25:26,528 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 17 2018-11-12 17:25:26,529 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date, dept_emp.emp_no AS dept_emp_emp_no, dept_emp.dept_no AS dept_emp_dept_no, dept_emp.from_date AS dept_emp_from_date, dept_emp.to_date AS dept_emp_to_date 18 FROM employees, dept_emp 19 WHERE employees.emp_no = dept_emp.emp_no AND employees.emp_no = %(emp_no_1)s 20 2018-11-12 17:25:26,529 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 21 [(Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F, Dept_emp empno=10010 deptno=d004), (Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F, Dept_emp empno=10010 deptno=d006)] 22 (Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F, Dept_emp empno=10010 deptno=d004) 23 (Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F, Dept_emp empno=10010 deptno=d006) 24 ========================================================================================== 25 26 2018-11-12 17:25:26,532 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 27 FROM employees INNER JOIN dept_emp ON employees.emp_no = dept_emp.emp_no 28 WHERE employees.emp_no = %(emp_no_1)s 29 2018-11-12 17:25:26,532 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 30 [Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F] 31 Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F 32 ========================================================================================== 33 34 2018-11-12 17:25:26,534 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 35 FROM employees INNER JOIN dept_emp ON employees.emp_no = dept_emp.emp_no 36 WHERE employees.emp_no = %(emp_no_1)s 37 2018-11-12 17:25:26,534 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 38 [Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F] 39 Employee no=10010 name='Duangkaew Piveteau' !!!gender=MyEnum.F gender=F 40 ========================================================================================== 41 42 43 Process finished with exit code 0
从表中看出,10010员工对应两个部门,本应显示两个,而且也没有部门信息,像第一种隐式方式,但是使用 join 方式 只显示一个
是因为:results = session.query(Employee).join(Dept_emp).filter(Employee.emp_no ==10010).all()
只返回一个实体对象,解决方法有两种,
一是,像隐式那样,将两个实体都传进去
二是,使用sqlalchemy.orm.relationship( 实体类名字符串)
测试第二种方法:
1 from sqlalchemy import create_engine,Column, Integer, String, Date 2 from sqlalchemy import Enum, ForeignKey, create_engine 3 from sqlalchemy.orm import sessionmaker, relationship 4 from sqlalchemy.ext.declarative import declarative_base 5 import sqlalchemy 6 7 import enum # 这里使用的是python 提供的 枚举,sqlalchemy 提供的enum 不能使用 8 9 class MyEnum(enum.Enum): 10 M = 'M' 11 F = 'F' 12 13 14 engine = create_engine('mysql+pymysql://root:123456@192.168.112.111:3306/test', echo=True) 15 Session = sessionmaker(bind=engine) 16 session = Session() 17 18 Base = declarative_base() 19 20 class Employee(Base): 21 __tablename__ = 'employees' 22 emp_no = Column(Integer, primary_key=True) 23 birth_date = Column() 24 first_name = Column() 25 last_name = Column() 26 gender = Column(Enum(MyEnum)) 27 hire_date = Column(Date) 28 29 # 因为从员工表获取 找部门,所以,关系,放在此处 30 departements = relationship('Dept_emp') # 关系,只是从一张表找另一张表用,并不是字段 31 32 def __repr__(self): 33 return "{} no={} name='{} {}'gender={} deps={}".format( 34 self.__class__.__name__,self.emp_no, self.first_name,self.last_name, 35 self.gender.value, 36 self.departements 37 ) 38 39 class Department(Base): 40 __tablename__ = 'departments' 41 dept_no = Column(primary_key=True) 42 dept_name = Column(unique=True) 43 44 def __repr__(self): 45 return '{} no={} name={}'.format( 46 type(self).__name__,self.dept_no,self.dept_name 47 ) 48 49 class Dept_emp(Base): 50 __tablename__ = 'dept_emp' 51 52 emp_no = Column(Integer, ForeignKey('employees.emp_no',ondelete='CASCADE'),primary_key=True) 53 dept_no = Column(ForeignKey('departments.dept_no',ondelete='CASCADE'),primary_key=True) 54 from_date = Column() 55 to_date = Column() 56 57 def __repr__(self): 58 return '{} empno={} deptno={}'.format( 59 type(self).__name__,self.emp_no,self.dept_no) 60 61 def show(emps): 62 for x in emps: 63 print(x) 64 print('======'*15, end='\n\n') 65 66 ''' 67 需求,查询10010员工 所在的部门编号及员工信息 68 ''' 69 70 # 第一种,因为没有提供等值条件,所以会自动生成join 条件,不推荐 71 results = session.query(Employee).join(Dept_emp).filter(Employee.emp_no == Dept_emp.emp_no).filter(Employee.emp_no == 10010) 72 print(results.all()) 73 74 # 第二种 75 results = session.query(Employee).join(Dept_emp, Employee.emp_no == Dept_emp.emp_no).filter(Employee.emp_no ==10010) 76 print(results.all()) 77 78 # 第三种 79 results = session.query(Employee).join(Dept_emp, (Employee.emp_no == Dept_emp.emp_no) & (Employee.emp_no == 10010)) 80 print(results.all())
结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt17.py 2 2018-11-12 17:49:18,365 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode' 3 2018-11-12 17:49:18,365 INFO sqlalchemy.engine.base.Engine {} 4 2018-11-12 17:49:18,367 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'lower_case_table_names' 5 2018-11-12 17:49:18,367 INFO sqlalchemy.engine.base.Engine {} 6 2018-11-12 17:49:18,368 INFO sqlalchemy.engine.base.Engine SELECT DATABASE() 7 2018-11-12 17:49:18,369 INFO sqlalchemy.engine.base.Engine {} 8 2018-11-12 17:49:18,370 INFO sqlalchemy.engine.base.Engine show collation where `Charset` = 'utf8mb4' and `Collation` = 'utf8mb4_bin' 9 2018-11-12 17:49:18,370 INFO sqlalchemy.engine.base.Engine {} 10 2018-11-12 17:49:18,372 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAR(60)) AS anon_1 11 2018-11-12 17:49:18,372 INFO sqlalchemy.engine.base.Engine {} 12 2018-11-12 17:49:18,373 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_1 13 2018-11-12 17:49:18,373 INFO sqlalchemy.engine.base.Engine {} 14 2018-11-12 17:49:18,374 INFO sqlalchemy.engine.base.Engine SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin AS anon_1 15 2018-11-12 17:49:18,374 INFO sqlalchemy.engine.base.Engine {} 16 2018-11-12 17:49:18,376 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 17 2018-11-12 17:49:18,377 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 18 FROM employees INNER JOIN dept_emp ON employees.emp_no = dept_emp.emp_no 19 WHERE employees.emp_no = dept_emp.emp_no AND employees.emp_no = %(emp_no_1)s 20 2018-11-12 17:49:18,377 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 21 2018-11-12 17:49:18,380 INFO sqlalchemy.engine.base.Engine SELECT dept_emp.emp_no AS dept_emp_emp_no, dept_emp.dept_no AS dept_emp_dept_no, dept_emp.from_date AS dept_emp_from_date, dept_emp.to_date AS dept_emp_to_date 22 FROM dept_emp 23 WHERE %(param_1)s = dept_emp.emp_no 24 2018-11-12 17:49:18,380 INFO sqlalchemy.engine.base.Engine {'param_1': 10010} 25 [Employee no=10010 name='Duangkaew Piveteau'gender=F deps=[Dept_emp empno=10010 deptno=d004, Dept_emp empno=10010 deptno=d006]] 26 2018-11-12 17:49:18,382 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 27 FROM employees INNER JOIN dept_emp ON employees.emp_no = dept_emp.emp_no 28 WHERE employees.emp_no = %(emp_no_1)s 29 2018-11-12 17:49:18,382 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 30 2018-11-12 17:49:18,384 INFO sqlalchemy.engine.base.Engine SELECT dept_emp.emp_no AS dept_emp_emp_no, dept_emp.dept_no AS dept_emp_dept_no, dept_emp.from_date AS dept_emp_from_date, dept_emp.to_date AS dept_emp_to_date 31 FROM dept_emp 32 WHERE %(param_1)s = dept_emp.emp_no 33 2018-11-12 17:49:18,384 INFO sqlalchemy.engine.base.Engine {'param_1': 10010} 34 [Employee no=10010 name='Duangkaew Piveteau'gender=F deps=[Dept_emp empno=10010 deptno=d004, Dept_emp empno=10010 deptno=d006]] 35 2018-11-12 17:49:18,386 INFO sqlalchemy.engine.base.Engine SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 36 FROM employees INNER JOIN dept_emp ON employees.emp_no = dept_emp.emp_no AND employees.emp_no = %(emp_no_1)s 37 2018-11-12 17:49:18,386 INFO sqlalchemy.engine.base.Engine {'emp_no_1': 10010} 38 2018-11-12 17:49:18,387 INFO sqlalchemy.engine.base.Engine SELECT dept_emp.emp_no AS dept_emp_emp_no, dept_emp.dept_no AS dept_emp_dept_no, dept_emp.from_date AS dept_emp_from_date, dept_emp.to_date AS dept_emp_to_date 39 FROM dept_emp 40 WHERE %(param_1)s = dept_emp.emp_no 41 2018-11-12 17:49:18,387 INFO sqlalchemy.engine.base.Engine {'param_1': 10010} 42 [Employee no=10010 name='Duangkaew Piveteau'gender=F deps=[Dept_emp empno=10010 deptno=d004, Dept_emp empno=10010 deptno=d006]] 43 44 Process finished with exit code 0
[Employee no=10010 name='Duangkaew Piveteau'gender=F deps=[Dept_emp empno=10010 deptno=d004, Dept_emp empno=10010 deptno=d006]]
可以看出: 一个emp_no 分配两个 dep_no
注意:
1 results = session.query(Employee).join(Dept_emp, (Employee.emp_no == Dept_emp.emp_no) & (Employee.emp_no == 10010)) 2 print(results.all()) 3 for x in results: 4 print(x) 5 print(x.emp_no) 6 print(x.departements)
结果:
1 D:\python3.7\python.exe E:/code_pycharm/test_in_class/tt17.py 2 [Employee no=10010 name='Duangkaew Piveteau'gender=F deps=[Dept_emp empno=10010 deptno=d004, Dept_emp empno=10010 deptno=d006]] 3 Employee no=10010 name='Duangkaew Piveteau'gender=F deps=[Dept_emp empno=10010 deptno=d004, Dept_emp empno=10010 deptno=d006] 4 10010 5 [Dept_emp empno=10010 deptno=d004, Dept_emp empno=10010 deptno=d006] 6 7 Process finished with exit code 0
可以看出,只要不访问 departements 属性,就不会差 dept_emp这张表