赞
踩
在一对多,或者多对多关系的时候,如果想要获取多的一方这一部分的数据的时候,往往能通过一个属性就可以全部获取了。
如有一个部门,想要这个部门下的所有员工,通过user.emp就可以获取所有的。
但有时候我们不想获取所有的数据,如只想获取范围更小的数据,那么这时候我们可以给relationship方法添加属性lazy=‘dynamic’,以后通过user.emp获取到的就不是一个列表,而是一个AppenderQuery对象了。这样就可以对这个对象再进行一层过滤和排序等操作。
from sqlalchemy import create_engine, Column, Integer, ForeignKey, String, TEXT, Boolean, DATE, DECIMAL from sqlalchemy.ext.declarative import declarative_base from datetime import date from sqlalchemy.orm import sessionmaker,relationship,backref #配置数据库 HOSTNAME = '127.0.0.1' PORT = '3306' DATABASE = 'test' USERNAME = 'root' PASSWORD = 'root' DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE) #创建数据库引擎 engine=create_engine(DB_URI) #创建基类,所有的模型类继承基类 Base=declarative_base(engine) #创建session session=sessionmaker(engine)()
非懒加载
#创建模型类 class Dept(Base): __tablename__='t_dept2' dept_no=Column(name='dept_no',type_=Integer,primary_key=True,autoincrement=True) dept_name=Column(name='dept_name',type_=String(20)) city=Column(name='city',type_=String(20)) #代表当前部门下的所有员工列表,这种写法不是最好的,最优的写法只要在一个对象中关联就可以了 #emp=relationship('Emp') #参数必须是另一个关联模型类的类名 def __str__(self): return f'部门编号:{self.dept_no}部门:{self.dept_name}城市:{self.city}' class Emp(Base): __tablename__='t_emp2' emp_no=Column(name='emp_no',type_=Integer,primary_key=True,autoincrement=True) emp_name=Column(name='emp_name',type_=String(20)) hire_date=Column(name='hire_date',type_=DATE) sal=Column(name='sal',type_=DECIMAL(10,2)) #todo 设置外键关联,在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段就可以了。从表中外键的字段,必须和主表的主键字段类型保持一致。 dept_no=Column(ForeignKey('t_dept2.dept_no',ondelete='CASCADE'),name='dept_no',type_=Integer) #代表员工所属的部门信息,backref:反向关联的属性名 dept=relationship('Dept',backref=backref('emps')) #参数必须是另一个关联模型类的类名 def __str__(self): return f'员工编号:{self.emp_no}员工姓名:{self.emp_name}员工入职时间:{self.hire_date}员工薪资:{self.sal}' #根据模型类建表 #Base.metadata.create_all() #Base.metadata.drop_all()
特别注意1:上述第26行代码默认为:lazy=‘select’,表示非懒加载
dept=relationship('Dept',backref=backref('emps',lazy='select'))
def query():
d1=session.query(Dept).filter(Dept.dept_no==1) #查询部门编号为1的部门信息
print(d1) #sql语句
print(type(d1)) #<class 'sqlalchemy.orm.query.Query'>
print(d1.first()) #查询部门编号为1的部门信息
print(d1.first().emps) #查询部门编号为1的下的所有员工信息,会查询出所有的数据
a、上述代码执行print(d1)
:打印sql语句
print(d1)
SELECT t_dept2.dept_no AS t_dept2_dept_no, t_dept2.dept_name AS t_dept2_dept_name, t_dept2.city AS t_dept2_city
FROM t_dept2
WHERE t_dept2.dept_no = %(dept_no_1)s
b、执行print(type(d1))
<class 'sqlalchemy.orm.query.Query'>
c、执行print(d1.first())
查询部门编号为1的部门信息
部门编号:1部门:信息部城市:北京
d、执行print(d1.first().emps)
查询部门编号为1的下的所有员工信息,会查询出所有的数据
[<__main__.Emp object at 0x00000267DD7877C0>, <__main__.Emp object at 0x00000267DD787AC0>, <__main__.Emp object at 0x00000267DD787820>, <__main__.Emp object at 0x00000267DD78A4C0>]
特别注意2:执行d1.first().emps会查询出所有的数据;加入部门表下有100w条数据,会一次性加载出来,因为默认lazy='select,会把所有关联属性的值都会查询出来;影响性能,会造成内存溢出
调试代码可以看出:数据被加载出来了;<class ‘sqlalchemy.orm.query.Query’>:不可以添加的query,由此不可以插入数据
懒加载
修改上述代码即可
#创建模型类 class Dept(Base): __tablename__='t_dept2' dept_no=Column(name='dept_no',type_=Integer,primary_key=True,autoincrement=True) dept_name=Column(name='dept_name',type_=String(20)) city=Column(name='city',type_=String(20)) #代表当前部门下的所有员工列表,这种写法不是最好的,最优的写法只要在一个对象中关联就可以了 #emp=relationship('Emp') #参数必须是另一个关联模型类的类名 def __str__(self): return f'部门编号:{self.dept_no}部门:{self.dept_name}城市:{self.city}' class Emp(Base): __tablename__='t_emp2' emp_no=Column(name='emp_no',type_=Integer,primary_key=True,autoincrement=True) emp_name=Column(name='emp_name',type_=String(20)) hire_date=Column(name='hire_date',type_=DATE) sal=Column(name='sal',type_=DECIMAL(10,2)) #todo 设置外键关联,在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段就可以了。从表中外键的字段,必须和主表的主键字段类型保持一致。 dept_no=Column(ForeignKey('t_dept2.dept_no',ondelete='CASCADE'),name='dept_no',type_=Integer) #代表员工所属的部门信息,backref:反向关联的属性名,lazy='dynamic:懒加载 dept=relationship('Dept',backref=backref('emps',lazy='dynamic')) #参数必须是另一个关联模型类的类名 def __str__(self): return f'员工编号:{self.emp_no}员工姓名:{self.emp_name}员工入职时间:{self.hire_date}员工薪资:{self.sal}' #根据模型类建表 #Base.metadata.create_all() #Base.metadata.drop_all()
def test_lazy():
d1=session.query(Dept).filter(Dept.dept_no==1)
print(d1.first()) #查询部门编号为1的部门信息
print(type(d1.first().emps)) #<class 'sqlalchemy.orm.dynamic.AppenderQuery'>
print(d1.first().emps) #sql语句
result=d1.first().emps
res=result.filter(Emp.sal>=6000).all()
print(res)
for i in res:
print(i)
a、执行print(d1.first())
:查询部门编号为1的部门信息
部门编号:1部门:信息部城市:北京
b、执行print(d1.first().emps)
:查询部门编号为1下的员工信息,由于懒加载模式,不会立即加载出数据,只有具体操作数据时,才会加载数据
SELECT t_emp2.emp_no AS t_emp2_emp_no, t_emp2.emp_name AS t_emp2_emp_name, t_emp2.hire_date AS t_emp2_hire_date, t_emp2.sal AS t_emp2_sal, t_emp2.dept_no AS t_emp2_dept_no
FROM t_emp2
WHERE %(param_1)s = t_emp2.dept_no
c、执行print(type(d1.first().emps))
<class 'sqlalchemy.orm.dynamic.AppenderQuery'>
d、执行以下代码:查询员工表总工资超过6000的员工信息
result=d1.first().emps
res=result.filter(Emp.sal>=6000).all() #查询员工表总工资超过6000的员工信息
print(res)
for i in res:
print(i)
[<__main__.Emp object at 0x00000282DE6AC910>, <__main__.Emp object at 0x00000282DE6ACCA0>, <__main__.Emp object at 0x00000282DE6ACC70>]
员工编号:1员工姓名:python员工入职时间:2020-01-01员工薪资:8888.88
员工编号:3员工姓名:javascript员工入职时间:2021-06-01员工薪资:6000.00
员工编号:4员工姓名:jmeter员工入职时间:2022-06-04员工薪资:10000.00
e1=Emp(emp_name='linux',hire_date='2019-12-01',sal=8000)
result.append(e1)
session.commit()
调试代码:类型为:AppenderQuery;可以添加的query,由此可以插入数据
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。